blob: 0f3f44eae2d3aa3d4814faec2f1915808270f4f3 [file] [log] [blame]
Chris Wren333a61c2014-05-28 16:40:57 -04001/*
2 * Copyright (C) 2014 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 */
16package com.android.server.notification;
17
Julia Reynoldsc65656a2018-02-12 09:55:14 -050018import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
Julia Reynolds85769912016-10-25 09:08:57 -040019import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
20import static android.app.NotificationManager.IMPORTANCE_HIGH;
21import static android.app.NotificationManager.IMPORTANCE_LOW;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060022import static android.app.NotificationManager.IMPORTANCE_MIN;
23import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
Julia Reynolds503ed942017-10-04 16:04:56 -040024import static android.service.notification.NotificationListenerService.Ranking
25 .USER_SENTIMENT_NEUTRAL;
Julia Reynoldsc65656a2018-02-12 09:55:14 -050026import static android.service.notification.NotificationListenerService.Ranking
27 .USER_SENTIMENT_POSITIVE;
Chris Wrenbdf33762015-12-04 15:50:51 -050028
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060029import android.annotation.Nullable;
30import android.app.ActivityManager;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060031import android.app.IActivityManager;
Chris Wren333a61c2014-05-28 16:40:57 -040032import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040033import android.app.NotificationChannel;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060034import android.content.ContentProvider;
35import android.content.ContentResolver;
Chris Wren333a61c2014-05-28 16:40:57 -040036import android.content.Context;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060037import android.content.Intent;
Tony Mantlerab55f0f2017-06-16 10:50:00 -070038import android.content.pm.PackageManager;
Chris Wren333a61c2014-05-28 16:40:57 -040039import android.content.pm.PackageManager.NameNotFoundException;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060040import android.content.pm.PackageManagerInternal;
Chris Wren333a61c2014-05-28 16:40:57 -040041import android.content.res.Resources;
42import android.graphics.Bitmap;
Dan Sandlerd63f9322015-05-06 15:18:49 -040043import android.graphics.drawable.Icon;
John Spurlockbfa5dc42014-07-28 23:30:45 -040044import android.media.AudioAttributes;
Julia Reynolds0c299d42016-11-15 14:37:04 -050045import android.media.AudioSystem;
Chris Wren9eb5e102017-01-26 13:15:06 -050046import android.metrics.LogMaker;
Julia Reynolds0c299d42016-11-15 14:37:04 -050047import android.net.Uri;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060048import android.os.Binder;
Julia Reynolds0c299d42016-11-15 14:37:04 -050049import android.os.Build;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040050import android.os.Bundle;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060051import android.os.IBinder;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060052import android.os.RemoteException;
Chris Wrenda4bd202014-09-04 15:53:52 -040053import android.os.UserHandle;
Julia Reynolds0c299d42016-11-15 14:37:04 -050054import android.provider.Settings;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040055import android.service.notification.Adjustment;
Julia Reynolds5d25ee72015-11-20 15:38:20 -050056import android.service.notification.NotificationListenerService;
Julia Reynoldsc9842c12017-02-07 12:46:41 -050057import android.service.notification.NotificationRecordProto;
Julia Reynolds503ed942017-10-04 16:04:56 -040058import android.service.notification.NotificationStats;
Julia Reynolds22f02b32016-12-01 15:05:13 -050059import android.service.notification.SnoozeCriterion;
Chris Wren333a61c2014-05-28 16:40:57 -040060import android.service.notification.StatusBarNotification;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -050061import android.text.TextUtils;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040062import android.util.ArraySet;
Julia Reynoldsf0f629f2016-02-25 09:34:04 -050063import android.util.Log;
Julia Reynolds2a128742016-11-28 14:29:25 -050064import android.util.TimeUtils;
Julia Reynoldsc9842c12017-02-07 12:46:41 -050065import android.util.proto.ProtoOutputStream;
Dan Sandler0a2308e2017-05-30 19:50:42 -040066import android.widget.RemoteViews;
John Spurlockbfa5dc42014-07-28 23:30:45 -040067
Chris Wren1031c972014-07-23 13:11:45 +000068import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -050069import com.android.internal.logging.MetricsLogger;
70import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Chris Wren6650e572015-05-15 17:19:25 -040071import com.android.server.EventLogTags;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060072import com.android.server.LocalServices;
Chris Wren333a61c2014-05-28 16:40:57 -040073
74import java.io.PrintWriter;
75import java.lang.reflect.Array;
Julia Reynolds22f02b32016-12-01 15:05:13 -050076import java.util.ArrayList;
Chris Wren333a61c2014-05-28 16:40:57 -040077import java.util.Arrays;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040078import java.util.List;
John Spurlock312d1d02014-07-08 10:24:57 -040079import java.util.Objects;
Chris Wren333a61c2014-05-28 16:40:57 -040080
81/**
82 * Holds data about notifications that should not be shared with the
83 * {@link android.service.notification.NotificationListenerService}s.
84 *
85 * <p>These objects should not be mutated unless the code is synchronized
Julia Reynolds88860ce2017-06-01 16:55:49 -040086 * on {@link NotificationManagerService#mNotificationLock}, and any
Chris Wren333a61c2014-05-28 16:40:57 -040087 * modification should be followed by a sorting of that list.</p>
88 *
89 * <p>Is sortable by {@link NotificationComparator}.</p>
90 *
91 * {@hide}
92 */
93public final class NotificationRecord {
Julia Reynoldsf0f629f2016-02-25 09:34:04 -050094 static final String TAG = "NotificationRecord";
95 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Chris Wrenb3921792017-06-01 13:34:46 -040096 private static final int MAX_LOGTAG_LENGTH = 35;
Chris Wren333a61c2014-05-28 16:40:57 -040097 final StatusBarNotification sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060098 final int mTargetSdkVersion;
Christoph Studer365e4c32014-09-18 20:35:36 +020099 final int mOriginalFlags;
Chris Wrenbdf33762015-12-04 15:50:51 -0500100 private final Context mContext;
Christoph Studer365e4c32014-09-18 20:35:36 +0200101
Chris Wren333a61c2014-05-28 16:40:57 -0400102 NotificationUsageStats.SingleNotificationStats stats;
103 boolean isCanceled;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600104 IBinder permissionOwner;
Chris Wren333a61c2014-05-28 16:40:57 -0400105
106 // These members are used by NotificationSignalExtractors
107 // to communicate with the ranking module.
108 private float mContactAffinity;
109 private boolean mRecentlyIntrusive;
Julia Reynolds309d1c82017-05-03 16:00:20 -0400110 private long mLastIntrusive;
Chris Wren333a61c2014-05-28 16:40:57 -0400111
112 // is this notification currently being intercepted by Zen Mode?
113 private boolean mIntercept;
Chris Wren333a61c2014-05-28 16:40:57 -0400114
Beverly5a20a5e2018-03-06 15:02:44 -0500115 // is this notification hidden since the app pkg is suspended?
116 private boolean mHidden;
117
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200118 // The timestamp used for ranking.
119 private long mRankingTimeMs;
120
Chris Wren640e3872015-04-21 13:23:18 -0400121 // The first post time, stable across updates.
122 private long mCreationTimeMs;
123
Chris Wren6650e572015-05-15 17:19:25 -0400124 // The most recent visibility event.
125 private long mVisibleSinceMs;
126
127 // The most recent update time, or the creation time if no updates.
128 private long mUpdateTimeMs;
129
Chris Wrena3446562014-06-03 18:11:47 -0400130 // Is this record an update of an old record?
131 public boolean isUpdate;
Chris Wren54bbef42014-07-09 18:37:56 -0400132 private int mPackagePriority;
Chris Wrena3446562014-06-03 18:11:47 -0400133
Chris Wren1031c972014-07-23 13:11:45 +0000134 private int mAuthoritativeRank;
Christoph Studercd4adf82014-08-19 17:50:49 +0200135 private String mGlobalSortKey;
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400136 private int mPackageVisibility;
Julia Reynoldsef37f282016-02-12 09:11:27 -0500137 private int mUserImportance = IMPORTANCE_UNSPECIFIED;
Chris Wren47633422016-01-22 09:56:59 -0500138 private int mImportance = IMPORTANCE_UNSPECIFIED;
Chris Wrenbdf33762015-12-04 15:50:51 -0500139 private CharSequence mImportanceExplanation = null;
Chris Wren1031c972014-07-23 13:11:45 +0000140
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500141 private int mSuppressedVisualEffects = 0;
Julia Reynoldsef37f282016-02-12 09:11:27 -0500142 private String mUserExplanation;
Chris Wrenbdf33762015-12-04 15:50:51 -0500143 private String mPeopleExplanation;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000144 private boolean mPreChannelsNotification = true;
Julia Reynolds0c299d42016-11-15 14:37:04 -0500145 private Uri mSound;
146 private long[] mVibration;
147 private AudioAttributes mAttributes;
Julia Reynolds924eed12017-01-19 09:52:07 -0500148 private NotificationChannel mChannel;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500149 private ArrayList<String> mPeopleOverride;
150 private ArrayList<SnoozeCriterion> mSnoozeCriteria;
Julia Reynolds924eed12017-01-19 09:52:07 -0500151 private boolean mShowBadge;
Chris Wren9eb5e102017-01-26 13:15:06 -0500152 private LogMaker mLogMaker;
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500153 private Light mLight;
Chris Wrenb3921792017-06-01 13:34:46 -0400154 private String mGroupLogTag;
155 private String mChannelIdLogTag;
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500156
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400157 private final List<Adjustment> mAdjustments;
Julia Reynolds503ed942017-10-04 16:04:56 -0400158 private final NotificationStats mStats;
159 private int mUserSentiment;
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500160 private boolean mIsInterruptive;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400161 private boolean mTextChanged;
162 private boolean mRecordedInterruption;
Kenny Guy23991102018-04-05 21:18:38 +0100163 private int mNumberOfSmartRepliesAdded;
164 private boolean mHasSeenSmartReplies;
Rohan Shah590e1b22018-04-10 23:48:47 -0400165 /**
166 * Whether this notification (and its channels) should be considered user locked. Used in
167 * conjunction with user sentiment calculation.
168 */
169 private boolean mIsAppImportanceLocked;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600170 private ArraySet<Uri> mGrantableUris;
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400171
Julia Reynolds924eed12017-01-19 09:52:07 -0500172 public NotificationRecord(Context context, StatusBarNotification sbn,
Rohan Shah590e1b22018-04-10 23:48:47 -0400173 NotificationChannel channel) {
Chris Wren333a61c2014-05-28 16:40:57 -0400174 this.sbn = sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600175 mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class)
176 .getPackageTargetSdkVersion(sbn.getPackageName());
Christoph Studer365e4c32014-09-18 20:35:36 +0200177 mOriginalFlags = sbn.getNotification().flags;
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200178 mRankingTimeMs = calculateRankingTimeMs(0L);
Chris Wren640e3872015-04-21 13:23:18 -0400179 mCreationTimeMs = sbn.getPostTime();
Chris Wren6650e572015-05-15 17:19:25 -0400180 mUpdateTimeMs = mCreationTimeMs;
Chris Wrenbdf33762015-12-04 15:50:51 -0500181 mContext = context;
Chris Wrencdee8cd2016-01-25 17:10:30 -0500182 stats = new NotificationUsageStats.SingleNotificationStats();
Julia Reynolds924eed12017-01-19 09:52:07 -0500183 mChannel = channel;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000184 mPreChannelsNotification = isPreChannelsNotification();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500185 mSound = calculateSound();
186 mVibration = calculateVibration();
187 mAttributes = calculateAttributes();
188 mImportance = calculateImportance();
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500189 mLight = calculateLights();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400190 mAdjustments = new ArrayList<>();
Julia Reynolds503ed942017-10-04 16:04:56 -0400191 mStats = new NotificationStats();
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500192 calculateUserSentiment();
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600193 calculateGrantableUris();
Chris Wrenbdf33762015-12-04 15:50:51 -0500194 }
195
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000196 private boolean isPreChannelsNotification() {
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600197 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) {
198 if (mTargetSdkVersion < Build.VERSION_CODES.O) {
199 return true;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000200 }
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000201 }
202 return false;
203 }
204
Julia Reynolds0c299d42016-11-15 14:37:04 -0500205 private Uri calculateSound() {
Chris Wrenbdf33762015-12-04 15:50:51 -0500206 final Notification n = sbn.getNotification();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500207
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700208 // No notification sounds on tv
209 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
210 return null;
211 }
212
Julia Reynolds924eed12017-01-19 09:52:07 -0500213 Uri sound = mChannel.getSound();
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000214 if (mPreChannelsNotification && (getChannel().getUserLockedFields()
Julia Reynolds0c299d42016-11-15 14:37:04 -0500215 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
216
217 final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0;
218 if (useDefaultSound) {
219 sound = Settings.System.DEFAULT_NOTIFICATION_URI;
Julia Reynoldsb9e712e2017-04-17 10:31:03 -0400220 } else {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500221 sound = n.sound;
222 }
223 }
224 return sound;
225 }
226
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500227 private Light calculateLights() {
228 int defaultLightColor = mContext.getResources().getColor(
229 com.android.internal.R.color.config_defaultNotificationColor);
230 int defaultLightOn = mContext.getResources().getInteger(
231 com.android.internal.R.integer.config_defaultNotificationLedOn);
232 int defaultLightOff = mContext.getResources().getInteger(
233 com.android.internal.R.integer.config_defaultNotificationLedOff);
234
Julia Reynolds529e3322017-02-06 08:33:01 -0500235 int channelLightColor = getChannel().getLightColor() != 0 ? getChannel().getLightColor()
236 : defaultLightColor;
237 Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500238 defaultLightOn, defaultLightOff) : null;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000239 if (mPreChannelsNotification
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500240 && (getChannel().getUserLockedFields()
241 & NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
242 final Notification notification = sbn.getNotification();
243 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
244 light = new Light(notification.ledARGB, notification.ledOnMS,
245 notification.ledOffMS);
246 if ((notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
247 light = new Light(defaultLightColor, defaultLightOn,
248 defaultLightOff);
249 }
250 } else {
251 light = null;
252 }
253 }
254 return light;
255 }
256
Julia Reynolds0c299d42016-11-15 14:37:04 -0500257 private long[] calculateVibration() {
258 long[] vibration;
259 final long[] defaultVibration = NotificationManagerService.getLongArray(
260 mContext.getResources(),
261 com.android.internal.R.array.config_defaultNotificationVibePattern,
262 NotificationManagerService.VIBRATE_PATTERN_MAXLEN,
263 NotificationManagerService.DEFAULT_VIBRATE_PATTERN);
264 if (getChannel().shouldVibrate()) {
Julia Reynoldsf57de462016-11-23 11:31:46 -0500265 vibration = getChannel().getVibrationPattern() == null
266 ? defaultVibration : getChannel().getVibrationPattern();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500267 } else {
268 vibration = null;
269 }
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000270 if (mPreChannelsNotification
Julia Reynolds0c299d42016-11-15 14:37:04 -0500271 && (getChannel().getUserLockedFields()
272 & NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
273 final Notification notification = sbn.getNotification();
274 final boolean useDefaultVibrate =
275 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
276 if (useDefaultVibrate) {
277 vibration = defaultVibration;
278 } else {
279 vibration = notification.vibrate;
280 }
281 }
282 return vibration;
283 }
284
285 private AudioAttributes calculateAttributes() {
286 final Notification n = sbn.getNotification();
Julia Reynolds619a69f2017-01-27 15:11:38 -0500287 AudioAttributes attributes = getChannel().getAudioAttributes();
288 if (attributes == null) {
289 attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
290 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500291
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000292 if (mPreChannelsNotification
Julia Reynolds619a69f2017-01-27 15:11:38 -0500293 && (getChannel().getUserLockedFields()
294 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
295 if (n.audioAttributes != null) {
296 // prefer audio attributes to stream type
297 attributes = n.audioAttributes;
298 } else if (n.audioStreamType >= 0
299 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
300 // the stream type is valid, use it
301 attributes = new AudioAttributes.Builder()
302 .setInternalLegacyStreamType(n.audioStreamType)
303 .build();
304 } else if (n.audioStreamType != AudioSystem.STREAM_DEFAULT) {
305 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
306 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500307 }
308 return attributes;
309 }
310
311 private int calculateImportance() {
312 final Notification n = sbn.getNotification();
313 int importance = getChannel().getImportance();
314 int requestedImportance = IMPORTANCE_DEFAULT;
Chris Wrenbdf33762015-12-04 15:50:51 -0500315
316 // Migrate notification flags to scores
317 if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) {
318 n.priority = Notification.PRIORITY_MAX;
319 }
320
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500321 n.priority = NotificationManagerService.clamp(n.priority, Notification.PRIORITY_MIN,
322 Notification.PRIORITY_MAX);
Chris Wrenbdf33762015-12-04 15:50:51 -0500323 switch (n.priority) {
324 case Notification.PRIORITY_MIN:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500325 requestedImportance = IMPORTANCE_MIN;
Julia Reynoldsf0f629f2016-02-25 09:34:04 -0500326 break;
Chris Wrenbdf33762015-12-04 15:50:51 -0500327 case Notification.PRIORITY_LOW:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500328 requestedImportance = IMPORTANCE_LOW;
Chris Wrenbdf33762015-12-04 15:50:51 -0500329 break;
330 case Notification.PRIORITY_DEFAULT:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500331 requestedImportance = IMPORTANCE_DEFAULT;
Chris Wrenbdf33762015-12-04 15:50:51 -0500332 break;
333 case Notification.PRIORITY_HIGH:
Chris Wrenbdf33762015-12-04 15:50:51 -0500334 case Notification.PRIORITY_MAX:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500335 requestedImportance = IMPORTANCE_HIGH;
Chris Wrenbdf33762015-12-04 15:50:51 -0500336 break;
337 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500338 stats.requestedImportance = requestedImportance;
339 stats.isNoisy = mSound != null || mVibration != null;
Chris Wrenbdf33762015-12-04 15:50:51 -0500340
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000341 if (mPreChannelsNotification
Julia Reynoldsa917a112017-03-21 11:09:14 -0400342 && (importance == IMPORTANCE_UNSPECIFIED
343 || (getChannel().getUserLockedFields()
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500344 & USER_LOCKED_IMPORTANCE) == 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500345 if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) {
346 requestedImportance = IMPORTANCE_LOW;
Julia Reynolds83fa1072016-02-17 09:10:19 -0500347 }
Julia Reynolds83fa1072016-02-17 09:10:19 -0500348
Julia Reynolds0c299d42016-11-15 14:37:04 -0500349 if (stats.isNoisy) {
350 if (requestedImportance < IMPORTANCE_DEFAULT) {
351 requestedImportance = IMPORTANCE_DEFAULT;
352 }
353 }
354
355 if (n.fullScreenIntent != null) {
356 requestedImportance = IMPORTANCE_HIGH;
357 }
358 importance = requestedImportance;
Chris Wrenbdf33762015-12-04 15:50:51 -0500359 }
360
Chris Wrencdee8cd2016-01-25 17:10:30 -0500361 stats.naturalImportance = importance;
Chris Wrenbdf33762015-12-04 15:50:51 -0500362 return importance;
Chris Wren333a61c2014-05-28 16:40:57 -0400363 }
364
365 // copy any notes that the ranking system may have made before the update
366 public void copyRankingInformation(NotificationRecord previous) {
367 mContactAffinity = previous.mContactAffinity;
368 mRecentlyIntrusive = previous.mRecentlyIntrusive;
Chris Wren54bbef42014-07-09 18:37:56 -0400369 mPackagePriority = previous.mPackagePriority;
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400370 mPackageVisibility = previous.mPackageVisibility;
Chris Wren333a61c2014-05-28 16:40:57 -0400371 mIntercept = previous.mIntercept;
Beverly5a20a5e2018-03-06 15:02:44 -0500372 mHidden = previous.mHidden;
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200373 mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
Chris Wren640e3872015-04-21 13:23:18 -0400374 mCreationTimeMs = previous.mCreationTimeMs;
Chris Wren6650e572015-05-15 17:19:25 -0400375 mVisibleSinceMs = previous.mVisibleSinceMs;
Selim Cinek5b03ce92016-05-18 15:16:58 -0700376 if (previous.sbn.getOverrideGroupKey() != null && !sbn.isAppGroup()) {
Chris Wren8a1638f2016-05-02 16:19:14 -0400377 sbn.setOverrideGroupKey(previous.sbn.getOverrideGroupKey());
378 }
Chris Wren1f602dc2016-04-11 10:33:46 -0400379 // Don't copy importance information or mGlobalSortKey, recompute them.
Chris Wren333a61c2014-05-28 16:40:57 -0400380 }
381
382 public Notification getNotification() { return sbn.getNotification(); }
383 public int getFlags() { return sbn.getNotification().flags; }
Chris Wrenda4bd202014-09-04 15:53:52 -0400384 public UserHandle getUser() { return sbn.getUser(); }
Chris Wren333a61c2014-05-28 16:40:57 -0400385 public String getKey() { return sbn.getKey(); }
Chris Wrenda4bd202014-09-04 15:53:52 -0400386 /** @deprecated Use {@link #getUser()} instead. */
387 public int getUserId() { return sbn.getUserId(); }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600388 public int getUid() { return sbn.getUid(); }
Chris Wren333a61c2014-05-28 16:40:57 -0400389
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800390 void dump(ProtoOutputStream proto, long fieldId, boolean redact, int state) {
391 final long token = proto.start(fieldId);
392
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500393 proto.write(NotificationRecordProto.KEY, sbn.getKey());
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800394 proto.write(NotificationRecordProto.STATE, state);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500395 if (getChannel() != null) {
396 proto.write(NotificationRecordProto.CHANNEL_ID, getChannel().getId());
397 }
398 proto.write(NotificationRecordProto.CAN_SHOW_LIGHT, getLight() != null);
399 proto.write(NotificationRecordProto.CAN_VIBRATE, getVibration() != null);
400 proto.write(NotificationRecordProto.FLAGS, sbn.getNotification().flags);
401 proto.write(NotificationRecordProto.GROUP_KEY, getGroupKey());
402 proto.write(NotificationRecordProto.IMPORTANCE, getImportance());
403 if (getSound() != null) {
404 proto.write(NotificationRecordProto.SOUND, getSound().toString());
405 }
406 if (getAudioAttributes() != null) {
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800407 getAudioAttributes().writeToProto(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500408 }
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800409
410 proto.end(token);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500411 }
412
Dan Sandler0a2308e2017-05-30 19:50:42 -0400413 String formatRemoteViews(RemoteViews rv) {
414 if (rv == null) return "null";
415 return String.format("%s/0x%08x (%d bytes): %s",
416 rv.getPackage(), rv.getLayoutId(), rv.estimateMemoryUsage(), rv.toString());
417 }
418
Dan Sandlera1770312015-07-10 13:59:29 -0400419 void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
Chris Wren333a61c2014-05-28 16:40:57 -0400420 final Notification notification = sbn.getNotification();
Dan Sandlerd63f9322015-05-06 15:18:49 -0400421 final Icon icon = notification.getSmallIcon();
422 String iconStr = String.valueOf(icon);
423 if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
424 iconStr += " / " + idDebugString(baseContext, icon.getResPackage(), icon.getResId());
425 }
Chris Wren333a61c2014-05-28 16:40:57 -0400426 pw.println(prefix + this);
Dan Sandler0a2308e2017-05-30 19:50:42 -0400427 prefix = prefix + " ";
Julia Reynoldsa917a112017-03-21 11:09:14 -0400428 pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
429 pw.println(prefix + "icon=" + iconStr);
Julia Reynolds4db59552017-06-30 13:34:01 -0400430 pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400431 pw.println(prefix + "pri=" + notification.priority);
432 pw.println(prefix + "key=" + sbn.getKey());
Julia Reynolds503ed942017-10-04 16:04:56 -0400433 pw.println(prefix + "seen=" + mStats.hasSeen());
Julia Reynoldsa917a112017-03-21 11:09:14 -0400434 pw.println(prefix + "groupKey=" + getGroupKey());
435 pw.println(prefix + "fullscreenIntent=" + notification.fullScreenIntent);
436 pw.println(prefix + "contentIntent=" + notification.contentIntent);
437 pw.println(prefix + "deleteIntent=" + notification.deleteIntent);
Dan Sandler0b4ceb32017-03-29 14:13:55 -0400438
439 pw.print(prefix + "tickerText=");
440 if (!TextUtils.isEmpty(notification.tickerText)) {
441 final String ticker = notification.tickerText.toString();
442 if (redact) {
443 // if the string is long enough, we allow ourselves a few bytes for debugging
444 pw.print(ticker.length() > 16 ? ticker.substring(0,8) : "");
445 pw.println("...");
446 } else {
447 pw.println(ticker);
448 }
449 } else {
450 pw.println("null");
451 }
Dan Sandler0a2308e2017-05-30 19:50:42 -0400452 pw.println(prefix + "contentView=" + formatRemoteViews(notification.contentView));
453 pw.println(prefix + "bigContentView=" + formatRemoteViews(notification.bigContentView));
454 pw.println(prefix + "headsUpContentView="
455 + formatRemoteViews(notification.headsUpContentView));
456 pw.print(prefix + String.format("color=0x%08x", notification.color));
Julia Reynoldsbad42972017-04-25 13:52:49 -0400457 pw.println(prefix + "timeout="
458 + TimeUtils.formatForLogging(notification.getTimeoutAfter()));
Chris Wren333a61c2014-05-28 16:40:57 -0400459 if (notification.actions != null && notification.actions.length > 0) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400460 pw.println(prefix + "actions={");
Chris Wren333a61c2014-05-28 16:40:57 -0400461 final int N = notification.actions.length;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500462 for (int i = 0; i < N; i++) {
Chris Wren333a61c2014-05-28 16:40:57 -0400463 final Notification.Action action = notification.actions[i];
Chris Wren1ac52a92016-02-24 14:54:52 -0500464 if (action != null) {
465 pw.println(String.format("%s [%d] \"%s\" -> %s",
466 prefix,
467 i,
468 action.title,
469 action.actionIntent == null ? "null" : action.actionIntent.toString()
470 ));
471 }
Chris Wren333a61c2014-05-28 16:40:57 -0400472 }
473 pw.println(prefix + " }");
474 }
475 if (notification.extras != null && notification.extras.size() > 0) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400476 pw.println(prefix + "extras={");
Chris Wren333a61c2014-05-28 16:40:57 -0400477 for (String key : notification.extras.keySet()) {
478 pw.print(prefix + " " + key + "=");
479 Object val = notification.extras.get(key);
480 if (val == null) {
481 pw.println("null");
482 } else {
483 pw.print(val.getClass().getSimpleName());
Dan Sandlera1770312015-07-10 13:59:29 -0400484 if (redact && (val instanceof CharSequence || val instanceof String)) {
Chris Wren333a61c2014-05-28 16:40:57 -0400485 // redact contents from bugreports
486 } else if (val instanceof Bitmap) {
487 pw.print(String.format(" (%dx%d)",
488 ((Bitmap) val).getWidth(),
489 ((Bitmap) val).getHeight()));
490 } else if (val.getClass().isArray()) {
491 final int N = Array.getLength(val);
Dan Sandlera1770312015-07-10 13:59:29 -0400492 pw.print(" (" + N + ")");
493 if (!redact) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500494 for (int j = 0; j < N; j++) {
Dan Sandlera1770312015-07-10 13:59:29 -0400495 pw.println();
496 pw.print(String.format("%s [%d] %s",
497 prefix, j, String.valueOf(Array.get(val, j))));
498 }
499 }
Chris Wren333a61c2014-05-28 16:40:57 -0400500 } else {
501 pw.print(" (" + String.valueOf(val) + ")");
502 }
503 pw.println();
504 }
505 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400506 pw.println(prefix + "}");
Chris Wren333a61c2014-05-28 16:40:57 -0400507 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400508 pw.println(prefix + "stats=" + stats.toString());
509 pw.println(prefix + "mContactAffinity=" + mContactAffinity);
510 pw.println(prefix + "mRecentlyIntrusive=" + mRecentlyIntrusive);
511 pw.println(prefix + "mPackagePriority=" + mPackagePriority);
512 pw.println(prefix + "mPackageVisibility=" + mPackageVisibility);
513 pw.println(prefix + "mUserImportance="
Julia Reynoldsef37f282016-02-12 09:11:27 -0500514 + NotificationListenerService.Ranking.importanceToString(mUserImportance));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400515 pw.println(prefix + "mImportance="
Chris Wrenbdf33762015-12-04 15:50:51 -0500516 + NotificationListenerService.Ranking.importanceToString(mImportance));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400517 pw.println(prefix + "mImportanceExplanation=" + mImportanceExplanation);
Rohan Shah590e1b22018-04-10 23:48:47 -0400518 pw.println(prefix + "mIsAppImportanceLocked=" + mIsAppImportanceLocked);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400519 pw.println(prefix + "mIntercept=" + mIntercept);
Beverly5a20a5e2018-03-06 15:02:44 -0500520 pw.println(prefix + "mHidden==" + mHidden);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400521 pw.println(prefix + "mGlobalSortKey=" + mGlobalSortKey);
522 pw.println(prefix + "mRankingTimeMs=" + mRankingTimeMs);
523 pw.println(prefix + "mCreationTimeMs=" + mCreationTimeMs);
524 pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
525 pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
526 pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000527 if (mPreChannelsNotification) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400528 pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500529 notification.defaults, notification.flags));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400530 pw.println(prefix + "n.sound=" + notification.sound);
531 pw.println(prefix + "n.audioStreamType=" + notification.audioStreamType);
532 pw.println(prefix + "n.audioAttributes=" + notification.audioAttributes);
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500533 pw.println(prefix + String.format(" led=0x%08x onMs=%d offMs=%d",
534 notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400535 pw.println(prefix + "vibrate=" + Arrays.toString(notification.vibrate));
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500536 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400537 pw.println(prefix + "mSound= " + mSound);
538 pw.println(prefix + "mVibration= " + mVibration);
539 pw.println(prefix + "mAttributes= " + mAttributes);
540 pw.println(prefix + "mLight= " + mLight);
541 pw.println(prefix + "mShowBadge=" + mShowBadge);
Julia Reynolds4db59552017-06-30 13:34:01 -0400542 pw.println(prefix + "mColorized=" + notification.isColorized());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500543 pw.println(prefix + "mIsInterruptive=" + mIsInterruptive);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400544 pw.println(prefix + "effectiveNotificationChannel=" + getChannel());
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500545 if (getPeopleOverride() != null) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400546 pw.println(prefix + "overridePeople= " + TextUtils.join(",", getPeopleOverride()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500547 }
548 if (getSnoozeCriteria() != null) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400549 pw.println(prefix + "snoozeCriteria=" + TextUtils.join(",", getSnoozeCriteria()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500550 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400551 pw.println(prefix + "mAdjustments=" + mAdjustments);
Chris Wren333a61c2014-05-28 16:40:57 -0400552 }
553
554
555 static String idDebugString(Context baseContext, String packageName, int id) {
556 Context c;
557
558 if (packageName != null) {
559 try {
560 c = baseContext.createPackageContext(packageName, 0);
561 } catch (NameNotFoundException e) {
562 c = baseContext;
563 }
564 } else {
565 c = baseContext;
566 }
567
568 Resources r = c.getResources();
569 try {
570 return r.getResourceName(id);
571 } catch (Resources.NotFoundException e) {
572 return "<name unknown>";
573 }
574 }
575
576 @Override
577 public final String toString() {
578 return String.format(
Julia Reynolds85769912016-10-25 09:08:57 -0400579 "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s importance=%d key=%s" +
Rohan Shah590e1b22018-04-10 23:48:47 -0400580 "appImportanceLocked=%s: %s)",
Chris Wren333a61c2014-05-28 16:40:57 -0400581 System.identityHashCode(this),
582 this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(),
Julia Reynolds4db59552017-06-30 13:34:01 -0400583 this.sbn.getTag(), this.mImportance, this.sbn.getKey(),
Rohan Shah590e1b22018-04-10 23:48:47 -0400584 mIsAppImportanceLocked, this.sbn.getNotification());
Chris Wren333a61c2014-05-28 16:40:57 -0400585 }
586
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400587 public void addAdjustment(Adjustment adjustment) {
588 synchronized (mAdjustments) {
589 mAdjustments.add(adjustment);
590 }
591 }
592
593 public void applyAdjustments() {
594 synchronized (mAdjustments) {
595 for (Adjustment adjustment: mAdjustments) {
596 Bundle signals = adjustment.getSignals();
597 if (signals.containsKey(Adjustment.KEY_PEOPLE)) {
598 final ArrayList<String> people =
599 adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
600 setPeopleOverride(people);
601 }
602 if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) {
603 final ArrayList<SnoozeCriterion> snoozeCriterionList =
604 adjustment.getSignals().getParcelableArrayList(
605 Adjustment.KEY_SNOOZE_CRITERIA);
606 setSnoozeCriteria(snoozeCriterionList);
607 }
608 if (signals.containsKey(Adjustment.KEY_GROUP_KEY)) {
609 final String groupOverrideKey =
610 adjustment.getSignals().getString(Adjustment.KEY_GROUP_KEY);
611 setOverrideGroupKey(groupOverrideKey);
612 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400613 if (signals.containsKey(Adjustment.KEY_USER_SENTIMENT)) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500614 // Only allow user sentiment update from assistant if user hasn't already
615 // expressed a preference for this channel
Rohan Shah590e1b22018-04-10 23:48:47 -0400616 if (!mIsAppImportanceLocked
617 && (getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500618 setUserSentiment(adjustment.getSignals().getInt(
619 Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEUTRAL));
620 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400621 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400622 }
623 }
624 }
625
Rohan Shah590e1b22018-04-10 23:48:47 -0400626 public void setIsAppImportanceLocked(boolean isAppImportanceLocked) {
627 mIsAppImportanceLocked = isAppImportanceLocked;
628 calculateUserSentiment();
629 }
630
Chris Wren333a61c2014-05-28 16:40:57 -0400631 public void setContactAffinity(float contactAffinity) {
632 mContactAffinity = contactAffinity;
Chris Wrenbdf33762015-12-04 15:50:51 -0500633 if (mImportance < IMPORTANCE_DEFAULT &&
Chris Wrenc977f812016-06-13 21:24:53 +0000634 mContactAffinity > ValidateNotificationPeople.VALID_CONTACT) {
Chris Wrenbdf33762015-12-04 15:50:51 -0500635 setImportance(IMPORTANCE_DEFAULT, getPeopleExplanation());
636 }
Chris Wren333a61c2014-05-28 16:40:57 -0400637 }
638
639 public float getContactAffinity() {
640 return mContactAffinity;
641 }
642
John Spurlock1d881a12015-03-18 19:21:54 -0400643 public void setRecentlyIntrusive(boolean recentlyIntrusive) {
Chris Wren333a61c2014-05-28 16:40:57 -0400644 mRecentlyIntrusive = recentlyIntrusive;
Julia Reynolds309d1c82017-05-03 16:00:20 -0400645 if (recentlyIntrusive) {
646 mLastIntrusive = System.currentTimeMillis();
647 }
Chris Wren333a61c2014-05-28 16:40:57 -0400648 }
649
650 public boolean isRecentlyIntrusive() {
651 return mRecentlyIntrusive;
652 }
653
Julia Reynolds309d1c82017-05-03 16:00:20 -0400654 public long getLastIntrusive() {
655 return mLastIntrusive;
656 }
657
Chris Wren54bbef42014-07-09 18:37:56 -0400658 public void setPackagePriority(int packagePriority) {
John Spurlock6ac5f8d2014-07-18 11:27:54 -0400659 mPackagePriority = packagePriority;
Chris Wren54bbef42014-07-09 18:37:56 -0400660 }
661
662 public int getPackagePriority() {
663 return mPackagePriority;
664 }
665
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400666 public void setPackageVisibilityOverride(int packageVisibility) {
667 mPackageVisibility = packageVisibility;
668 }
669
670 public int getPackageVisibilityOverride() {
671 return mPackageVisibility;
672 }
673
Julia Reynoldsef37f282016-02-12 09:11:27 -0500674 public void setUserImportance(int importance) {
675 mUserImportance = importance;
676 applyUserImportance();
Chris Wrenbdf33762015-12-04 15:50:51 -0500677 }
678
Julia Reynoldsef37f282016-02-12 09:11:27 -0500679 private String getUserExplanation() {
680 if (mUserExplanation == null) {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500681 mUserExplanation = mContext.getResources().getString(
682 com.android.internal.R.string.importance_from_user);
Chris Wrenbdf33762015-12-04 15:50:51 -0500683 }
Julia Reynoldsef37f282016-02-12 09:11:27 -0500684 return mUserExplanation;
Chris Wrenbdf33762015-12-04 15:50:51 -0500685 }
686
687 private String getPeopleExplanation() {
688 if (mPeopleExplanation == null) {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500689 mPeopleExplanation = mContext.getResources().getString(
690 com.android.internal.R.string.importance_from_person);
Chris Wrenbdf33762015-12-04 15:50:51 -0500691 }
692 return mPeopleExplanation;
693 }
694
Julia Reynoldsef37f282016-02-12 09:11:27 -0500695 private void applyUserImportance() {
Julia Reynolds85769912016-10-25 09:08:57 -0400696 if (mUserImportance != IMPORTANCE_UNSPECIFIED) {
Julia Reynoldsef37f282016-02-12 09:11:27 -0500697 mImportance = mUserImportance;
698 mImportanceExplanation = getUserExplanation();
Julia Reynolds5d25ee72015-11-20 15:38:20 -0500699 }
700 }
701
Julia Reynoldsef37f282016-02-12 09:11:27 -0500702 public int getUserImportance() {
703 return mUserImportance;
Julia Reynolds5d25ee72015-11-20 15:38:20 -0500704 }
705
Chris Wrenbdf33762015-12-04 15:50:51 -0500706 public void setImportance(int importance, CharSequence explanation) {
Julia Reynolds85769912016-10-25 09:08:57 -0400707 if (importance != IMPORTANCE_UNSPECIFIED) {
Chris Wrenbdf33762015-12-04 15:50:51 -0500708 mImportance = importance;
709 mImportanceExplanation = explanation;
710 }
Julia Reynoldsef37f282016-02-12 09:11:27 -0500711 applyUserImportance();
Chris Wrenbdf33762015-12-04 15:50:51 -0500712 }
713
714 public int getImportance() {
715 return mImportance;
716 }
717
718 public CharSequence getImportanceExplanation() {
719 return mImportanceExplanation;
720 }
721
Chris Wren333a61c2014-05-28 16:40:57 -0400722 public boolean setIntercepted(boolean intercept) {
723 mIntercept = intercept;
724 return mIntercept;
725 }
726
727 public boolean isIntercepted() {
728 return mIntercept;
729 }
730
Beverly5a20a5e2018-03-06 15:02:44 -0500731 public void setHidden(boolean hidden) {
732 mHidden = hidden;
733 }
734
735 public boolean isHidden() {
736 return mHidden;
737 }
738
739
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500740 public void setSuppressedVisualEffects(int effects) {
741 mSuppressedVisualEffects = effects;
742 }
743
744 public int getSuppressedVisualEffects() {
745 return mSuppressedVisualEffects;
746 }
747
John Spurlock312d1d02014-07-08 10:24:57 -0400748 public boolean isCategory(String category) {
John Spurlockbfa5dc42014-07-28 23:30:45 -0400749 return Objects.equals(getNotification().category, category);
750 }
751
John Spurlockbfa5dc42014-07-28 23:30:45 -0400752 public boolean isAudioAttributesUsage(int usage) {
Julia Reynolds51eb78f82018-03-07 07:35:21 -0500753 return mAttributes != null && mAttributes.getUsage() == usage;
John Spurlock312d1d02014-07-08 10:24:57 -0400754 }
755
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200756 /**
757 * Returns the timestamp to use for time-based sorting in the ranker.
758 */
759 public long getRankingTimeMs() {
760 return mRankingTimeMs;
761 }
762
763 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400764 * @param now this current time in milliseconds.
765 * @returns the number of milliseconds since the most recent update, or the post time if none.
Chris Wren6650e572015-05-15 17:19:25 -0400766 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400767 public int getFreshnessMs(long now) {
768 return (int) (now - mUpdateTimeMs);
Chris Wren6650e572015-05-15 17:19:25 -0400769 }
770
771 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400772 * @param now this current time in milliseconds.
773 * @returns the number of milliseconds since the the first post, ignoring updates.
Chris Wren640e3872015-04-21 13:23:18 -0400774 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400775 public int getLifespanMs(long now) {
776 return (int) (now - mCreationTimeMs);
Chris Wren640e3872015-04-21 13:23:18 -0400777 }
778
779 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400780 * @param now this current time in milliseconds.
781 * @returns the number of milliseconds since the most recent visibility event, or 0 if never.
Chris Wren6650e572015-05-15 17:19:25 -0400782 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400783 public int getExposureMs(long now) {
784 return mVisibleSinceMs == 0 ? 0 : (int) (now - mVisibleSinceMs);
Chris Wren6650e572015-05-15 17:19:25 -0400785 }
786
787 /**
788 * Set the visibility of the notification.
789 */
Dieter Hsud39f0d52018-04-14 02:08:30 +0800790 public void setVisibility(boolean visible, int rank, int count) {
Chris Wren6650e572015-05-15 17:19:25 -0400791 final long now = System.currentTimeMillis();
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400792 mVisibleSinceMs = visible ? now : mVisibleSinceMs;
Chris Wren6650e572015-05-15 17:19:25 -0400793 stats.onVisibilityChanged(visible);
Chris Wren9eb5e102017-01-26 13:15:06 -0500794 MetricsLogger.action(getLogMaker(now)
795 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
796 .setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800797 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
798 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count));
Chris Wren9eb5e102017-01-26 13:15:06 -0500799 if (visible) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400800 setSeen();
Chris Wren9eb5e102017-01-26 13:15:06 -0500801 MetricsLogger.histogram(mContext, "note_freshness", getFreshnessMs(now));
802 }
Chris Wren6650e572015-05-15 17:19:25 -0400803 EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0,
Chris Wren9eb5e102017-01-26 13:15:06 -0500804 getLifespanMs(now),
805 getFreshnessMs(now),
Chris Wrend1dbc922015-06-19 17:51:16 -0400806 0, // exposure time
807 rank);
Chris Wren6650e572015-05-15 17:19:25 -0400808 }
809
810 /**
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200811 * @param previousRankingTimeMs for updated notifications, {@link #getRankingTimeMs()}
812 * of the previous notification record, 0 otherwise
813 */
814 private long calculateRankingTimeMs(long previousRankingTimeMs) {
815 Notification n = getNotification();
816 // Take developer provided 'when', unless it's in the future.
817 if (n.when != 0 && n.when <= sbn.getPostTime()) {
818 return n.when;
819 }
820 // If we've ranked a previous instance with a timestamp, inherit it. This case is
821 // important in order to have ranking stability for updating notifications.
822 if (previousRankingTimeMs > 0) {
823 return previousRankingTimeMs;
824 }
825 return sbn.getPostTime();
826 }
Chris Wren1031c972014-07-23 13:11:45 +0000827
Christoph Studercd4adf82014-08-19 17:50:49 +0200828 public void setGlobalSortKey(String globalSortKey) {
829 mGlobalSortKey = globalSortKey;
Chris Wren1031c972014-07-23 13:11:45 +0000830 }
831
Christoph Studercd4adf82014-08-19 17:50:49 +0200832 public String getGlobalSortKey() {
833 return mGlobalSortKey;
Chris Wren1031c972014-07-23 13:11:45 +0000834 }
835
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700836 /** Check if any of the listeners have marked this notification as seen by the user. */
837 public boolean isSeen() {
Julia Reynolds503ed942017-10-04 16:04:56 -0400838 return mStats.hasSeen();
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700839 }
840
841 /** Mark the notification as seen by the user. */
842 public void setSeen() {
Julia Reynolds503ed942017-10-04 16:04:56 -0400843 mStats.setSeen();
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400844 if (mTextChanged) {
845 mIsInterruptive = true;
846 }
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700847 }
848
Chris Wren1031c972014-07-23 13:11:45 +0000849 public void setAuthoritativeRank(int authoritativeRank) {
850 mAuthoritativeRank = authoritativeRank;
851 }
852
853 public int getAuthoritativeRank() {
854 return mAuthoritativeRank;
855 }
856
857 public String getGroupKey() {
858 return sbn.getGroupKey();
859 }
Chris Wren47633422016-01-22 09:56:59 -0500860
Chris Wrenb3921792017-06-01 13:34:46 -0400861 public void setOverrideGroupKey(String overrideGroupKey) {
862 sbn.setOverrideGroupKey(overrideGroupKey);
863 mGroupLogTag = null;
864 }
865
866 private String getGroupLogTag() {
867 if (mGroupLogTag == null) {
868 mGroupLogTag = shortenTag(sbn.getGroup());
869 }
870 return mGroupLogTag;
871 }
872
873 private String getChannelIdLogTag() {
874 if (mChannelIdLogTag == null) {
875 mChannelIdLogTag = shortenTag(mChannel.getId());
876 }
877 return mChannelIdLogTag;
878 }
879
880 private String shortenTag(String longTag) {
881 if (longTag == null) {
882 return null;
883 }
884 if (longTag.length() < MAX_LOGTAG_LENGTH) {
885 return longTag;
886 } else {
887 return longTag.substring(0, MAX_LOGTAG_LENGTH - 8) + "-" +
888 Integer.toHexString(longTag.hashCode());
889 }
890 }
891
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400892 public NotificationChannel getChannel() {
Julia Reynolds924eed12017-01-19 09:52:07 -0500893 return mChannel;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500894 }
895
Rohan Shah590e1b22018-04-10 23:48:47 -0400896 /**
897 * @see RankingHelper#getIsAppImportanceLocked(String, int)
898 */
899 public boolean getIsAppImportanceLocked() {
900 return mIsAppImportanceLocked;
901 }
902
Julia Reynolds924eed12017-01-19 09:52:07 -0500903 protected void updateNotificationChannel(NotificationChannel channel) {
904 if (channel != null) {
905 mChannel = channel;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500906 calculateImportance();
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500907 calculateUserSentiment();
Julia Reynolds22f02b32016-12-01 15:05:13 -0500908 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400909 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500910
Julia Reynolds924eed12017-01-19 09:52:07 -0500911 public void setShowBadge(boolean showBadge) {
912 mShowBadge = showBadge;
913 }
914
915 public boolean canShowBadge() {
916 return mShowBadge;
917 }
918
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500919 public Light getLight() {
920 return mLight;
921 }
922
Julia Reynolds0c299d42016-11-15 14:37:04 -0500923 public Uri getSound() {
924 return mSound;
925 }
926
927 public long[] getVibration() {
928 return mVibration;
929 }
930
931 public AudioAttributes getAudioAttributes() {
932 return mAttributes;
933 }
Julia Reynolds22f02b32016-12-01 15:05:13 -0500934
935 public ArrayList<String> getPeopleOverride() {
936 return mPeopleOverride;
937 }
938
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500939 public void setInterruptive(boolean interruptive) {
940 mIsInterruptive = interruptive;
941 }
942
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400943 public void setTextChanged(boolean textChanged) {
944 mTextChanged = textChanged;
945 }
946
947 public void setRecordedInterruption(boolean recorded) {
948 mRecordedInterruption = recorded;
949 }
950
951 public boolean hasRecordedInterruption() {
952 return mRecordedInterruption;
953 }
954
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500955 public boolean isInterruptive() {
956 return mIsInterruptive;
957 }
958
Julia Reynolds22f02b32016-12-01 15:05:13 -0500959 protected void setPeopleOverride(ArrayList<String> people) {
960 mPeopleOverride = people;
961 }
962
963 public ArrayList<SnoozeCriterion> getSnoozeCriteria() {
964 return mSnoozeCriteria;
965 }
966
967 protected void setSnoozeCriteria(ArrayList<SnoozeCriterion> snoozeCriteria) {
968 mSnoozeCriteria = snoozeCriteria;
969 }
Chris Wren9eb5e102017-01-26 13:15:06 -0500970
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500971 private void calculateUserSentiment() {
Rohan Shah590e1b22018-04-10 23:48:47 -0400972 if ((getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0
973 || mIsAppImportanceLocked) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500974 mUserSentiment = USER_SENTIMENT_POSITIVE;
975 }
976 }
977
Julia Reynolds503ed942017-10-04 16:04:56 -0400978 private void setUserSentiment(int userSentiment) {
979 mUserSentiment = userSentiment;
980 }
981
982 public int getUserSentiment() {
983 return mUserSentiment;
984 }
985
986 public NotificationStats getStats() {
987 return mStats;
988 }
989
990 public void recordExpanded() {
991 mStats.setExpanded();
992 }
993
994 public void recordDirectReplied() {
995 mStats.setDirectReplied();
996 }
997
998 public void recordDismissalSurface(@NotificationStats.DismissalSurface int surface) {
999 mStats.setDismissalSurface(surface);
1000 }
1001
1002 public void recordSnoozed() {
1003 mStats.setSnoozed();
1004 }
1005
1006 public void recordViewedSettings() {
1007 mStats.setViewedSettings();
1008 }
1009
Kenny Guy23991102018-04-05 21:18:38 +01001010 public void setNumSmartRepliesAdded(int noReplies) {
1011 mNumberOfSmartRepliesAdded = noReplies;
1012 }
1013
1014 public int getNumSmartRepliesAdded() {
1015 return mNumberOfSmartRepliesAdded;
1016 }
1017
1018 public boolean hasSeenSmartReplies() {
1019 return mHasSeenSmartReplies;
1020 }
1021
1022 public void setSeenSmartReplies(boolean hasSeenSmartReplies) {
1023 mHasSeenSmartReplies = hasSeenSmartReplies;
1024 }
1025
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001026 /**
1027 * @return all {@link Uri} that should have permission granted to whoever
1028 * will be rendering it. This list has already been vetted to only
1029 * include {@link Uri} that the enqueuing app can grant.
1030 */
1031 public @Nullable ArraySet<Uri> getGrantableUris() {
1032 return mGrantableUris;
1033 }
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001034
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001035 /**
1036 * Collect all {@link Uri} that should have permission granted to whoever
1037 * will be rendering it.
1038 */
1039 private void calculateGrantableUris() {
1040 final Notification notification = getNotification();
Jeff Sharkey23b31182018-04-18 21:32:12 -06001041 notification.visitUris((uri) -> {
1042 visitGrantableUri(uri);
1043 });
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001044
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001045 if (notification.getChannelId() != null) {
1046 NotificationChannel channel = getChannel();
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001047 if (channel != null) {
Jeff Sharkey23b31182018-04-18 21:32:12 -06001048 visitGrantableUri(channel.getSound());
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001049 }
1050 }
1051 }
1052
1053 /**
1054 * Note the presence of a {@link Uri} that should have permission granted to
1055 * whoever will be rendering it.
1056 * <p>
1057 * If the enqueuing app has the ability to grant access, it will be added to
1058 * {@link #mGrantableUris}. Otherwise, this will either log or throw
1059 * {@link SecurityException} depending on target SDK of enqueuing app.
1060 */
Jeff Sharkey23b31182018-04-18 21:32:12 -06001061 private void visitGrantableUri(Uri uri) {
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001062 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
1063
1064 // We can't grant Uri permissions from system
1065 final int sourceUid = sbn.getUid();
1066 if (sourceUid == android.os.Process.SYSTEM_UID) return;
1067
1068 final IActivityManager am = ActivityManager.getService();
1069 final long ident = Binder.clearCallingIdentity();
1070 try {
1071 // This will throw SecurityException if caller can't grant
1072 am.checkGrantUriPermission(sourceUid, null,
1073 ContentProvider.getUriWithoutUserId(uri),
1074 Intent.FLAG_GRANT_READ_URI_PERMISSION,
1075 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
1076
1077 if (mGrantableUris == null) {
1078 mGrantableUris = new ArraySet<>();
1079 }
1080 mGrantableUris.add(uri);
1081 } catch (RemoteException ignored) {
1082 // Ignored because we're in same process
1083 } catch (SecurityException e) {
1084 if (mTargetSdkVersion >= Build.VERSION_CODES.P) {
1085 throw e;
1086 } else {
1087 Log.w(TAG, "Ignoring " + uri + " from " + sourceUid + ": " + e.getMessage());
1088 }
1089 } finally {
1090 Binder.restoreCallingIdentity(ident);
1091 }
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001092 }
1093
Chris Wren9eb5e102017-01-26 13:15:06 -05001094 public LogMaker getLogMaker(long now) {
1095 if (mLogMaker == null) {
Chris Wrenb3921792017-06-01 13:34:46 -04001096 // initialize fields that only change on update (so a new record)
Chris Wren9eb5e102017-01-26 13:15:06 -05001097 mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
1098 .setPackageName(sbn.getPackageName())
1099 .addTaggedData(MetricsEvent.NOTIFICATION_ID, sbn.getId())
Chris Wrenb3921792017-06-01 13:34:46 -04001100 .addTaggedData(MetricsEvent.NOTIFICATION_TAG, sbn.getTag())
1101 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag());
Chris Wren9eb5e102017-01-26 13:15:06 -05001102 }
Chris Wrenb3921792017-06-01 13:34:46 -04001103 // reset fields that can change between updates, or are used by multiple logs
Chris Wren9eb5e102017-01-26 13:15:06 -05001104 return mLogMaker
Chris Wrena7c1b802017-03-07 10:17:20 -05001105 .clearCategory()
1106 .clearType()
1107 .clearSubtype()
Chris Wren9eb5e102017-01-26 13:15:06 -05001108 .clearTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX)
Chris Wrenb3921792017-06-01 13:34:46 -04001109 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance)
1110 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
1111 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
1112 sbn.getNotification().isGroupSummary() ? 1 : 0)
Chris Wren9eb5e102017-01-26 13:15:06 -05001113 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now))
1114 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now))
1115 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now));
1116 }
1117
1118 public LogMaker getLogMaker() {
1119 return getLogMaker(System.currentTimeMillis());
1120 }
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05001121
1122 @VisibleForTesting
1123 static final class Light {
1124 public final int color;
1125 public final int onMs;
1126 public final int offMs;
1127
1128 public Light(int color, int onMs, int offMs) {
1129 this.color = color;
1130 this.onMs = onMs;
1131 this.offMs = offMs;
1132 }
1133
1134 @Override
1135 public boolean equals(Object o) {
1136 if (this == o) return true;
1137 if (o == null || getClass() != o.getClass()) return false;
1138
1139 Light light = (Light) o;
1140
1141 if (color != light.color) return false;
1142 if (onMs != light.onMs) return false;
1143 return offMs == light.offMs;
1144
1145 }
1146
1147 @Override
1148 public int hashCode() {
1149 int result = color;
1150 result = 31 * result + onMs;
1151 result = 31 * result + offMs;
1152 return result;
1153 }
1154
1155 @Override
1156 public String toString() {
1157 return "Light{" +
1158 "color=" + color +
1159 ", onMs=" + onMs +
1160 ", offMs=" + offMs +
1161 '}';
1162 }
1163 }
Chris Wren333a61c2014-05-28 16:40:57 -04001164}