blob: b9c0e6c41ace0ba0aae96c6f794bf439d43ace63 [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 Reynolds27c0a962018-12-10 12:37:28 -050024import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
25import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
Chris Wrenbdf33762015-12-04 15:50:51 -050026
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060027import android.annotation.Nullable;
28import android.app.ActivityManager;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060029import android.app.IActivityManager;
Chris Wren333a61c2014-05-28 16:40:57 -040030import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040031import android.app.NotificationChannel;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060032import android.content.ContentProvider;
33import android.content.ContentResolver;
Chris Wren333a61c2014-05-28 16:40:57 -040034import android.content.Context;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060035import android.content.Intent;
Tony Mantlerab55f0f2017-06-16 10:50:00 -070036import android.content.pm.PackageManager;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060037import android.content.pm.PackageManagerInternal;
Julia Reynoldsd61bdf12020-02-25 12:25:07 -050038import android.content.pm.ShortcutInfo;
Chris Wren333a61c2014-05-28 16:40:57 -040039import android.graphics.Bitmap;
John Spurlockbfa5dc42014-07-28 23:30:45 -040040import android.media.AudioAttributes;
Julia Reynolds0c299d42016-11-15 14:37:04 -050041import android.media.AudioSystem;
Chris Wren9eb5e102017-01-26 13:15:06 -050042import android.metrics.LogMaker;
Julia Reynolds0c299d42016-11-15 14:37:04 -050043import android.net.Uri;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060044import android.os.Binder;
Julia Reynolds0c299d42016-11-15 14:37:04 -050045import android.os.Build;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040046import android.os.Bundle;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060047import android.os.IBinder;
Chris Wrenda4bd202014-09-04 15:53:52 -040048import android.os.UserHandle;
Julia Reynolds0c299d42016-11-15 14:37:04 -050049import android.provider.Settings;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040050import android.service.notification.Adjustment;
Julia Reynolds5d25ee72015-11-20 15:38:20 -050051import android.service.notification.NotificationListenerService;
Julia Reynoldsc9842c12017-02-07 12:46:41 -050052import android.service.notification.NotificationRecordProto;
Julia Reynolds503ed942017-10-04 16:04:56 -040053import android.service.notification.NotificationStats;
Julia Reynolds22f02b32016-12-01 15:05:13 -050054import android.service.notification.SnoozeCriterion;
Chris Wren333a61c2014-05-28 16:40:57 -040055import android.service.notification.StatusBarNotification;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -050056import android.text.TextUtils;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040057import android.util.ArraySet;
Julia Reynoldsf0f629f2016-02-25 09:34:04 -050058import android.util.Log;
Julia Reynolds2a128742016-11-28 14:29:25 -050059import android.util.TimeUtils;
Julia Reynoldsc9842c12017-02-07 12:46:41 -050060import android.util.proto.ProtoOutputStream;
Dan Sandler0a2308e2017-05-30 19:50:42 -040061import android.widget.RemoteViews;
John Spurlockbfa5dc42014-07-28 23:30:45 -040062
Chris Wren1031c972014-07-23 13:11:45 +000063import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -050064import com.android.internal.logging.MetricsLogger;
65import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Chris Wren6650e572015-05-15 17:19:25 -040066import com.android.server.EventLogTags;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060067import com.android.server.LocalServices;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070068import com.android.server.uri.UriGrantsManagerInternal;
Chris Wren333a61c2014-05-28 16:40:57 -040069
70import java.io.PrintWriter;
71import java.lang.reflect.Array;
Julia Reynolds22f02b32016-12-01 15:05:13 -050072import java.util.ArrayList;
Chris Wren333a61c2014-05-28 16:40:57 -040073import java.util.Arrays;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040074import java.util.List;
John Spurlock312d1d02014-07-08 10:24:57 -040075import java.util.Objects;
Chris Wren333a61c2014-05-28 16:40:57 -040076
77/**
78 * Holds data about notifications that should not be shared with the
79 * {@link android.service.notification.NotificationListenerService}s.
80 *
81 * <p>These objects should not be mutated unless the code is synchronized
Julia Reynolds88860ce2017-06-01 16:55:49 -040082 * on {@link NotificationManagerService#mNotificationLock}, and any
Chris Wren333a61c2014-05-28 16:40:57 -040083 * modification should be followed by a sorting of that list.</p>
84 *
85 * <p>Is sortable by {@link NotificationComparator}.</p>
86 *
87 * {@hide}
88 */
89public final class NotificationRecord {
Julia Reynoldsf0f629f2016-02-25 09:34:04 -050090 static final String TAG = "NotificationRecord";
91 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Julia Reynoldsd6730072019-01-04 12:52:52 -050092 // the period after which a notification is updated where it can make sound
93 private static final int MAX_SOUND_DELAY_MS = 2000;
Julia Reynolds24edc002020-01-29 16:35:32 -050094 private final StatusBarNotification sbn;
Julia Reynolds218871e2018-06-13 10:45:21 -040095 IActivityManager mAm;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070096 UriGrantsManagerInternal mUgmInternal;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060097 final int mTargetSdkVersion;
Christoph Studer365e4c32014-09-18 20:35:36 +020098 final int mOriginalFlags;
Chris Wrenbdf33762015-12-04 15:50:51 -050099 private final Context mContext;
Christoph Studer365e4c32014-09-18 20:35:36 +0200100
Chris Wren333a61c2014-05-28 16:40:57 -0400101 NotificationUsageStats.SingleNotificationStats stats;
102 boolean isCanceled;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600103 IBinder permissionOwner;
Chris Wren333a61c2014-05-28 16:40:57 -0400104
105 // These members are used by NotificationSignalExtractors
106 // to communicate with the ranking module.
107 private float mContactAffinity;
108 private boolean mRecentlyIntrusive;
Julia Reynolds309d1c82017-05-03 16:00:20 -0400109 private long mLastIntrusive;
Chris Wren333a61c2014-05-28 16:40:57 -0400110
111 // is this notification currently being intercepted by Zen Mode?
112 private boolean mIntercept;
Chris Wren333a61c2014-05-28 16:40:57 -0400113
Beverly5a20a5e2018-03-06 15:02:44 -0500114 // is this notification hidden since the app pkg is suspended?
115 private boolean mHidden;
116
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200117 // The timestamp used for ranking.
118 private long mRankingTimeMs;
119
Chris Wren640e3872015-04-21 13:23:18 -0400120 // The first post time, stable across updates.
121 private long mCreationTimeMs;
122
Chris Wren6650e572015-05-15 17:19:25 -0400123 // The most recent visibility event.
124 private long mVisibleSinceMs;
125
126 // The most recent update time, or the creation time if no updates.
Julia Reynoldsd6730072019-01-04 12:52:52 -0500127 @VisibleForTesting
128 final long mUpdateTimeMs;
Chris Wren6650e572015-05-15 17:19:25 -0400129
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400130 // The most recent interruption time, or the creation time if no updates. Differs from the
131 // above value because updates are filtered based on whether they actually interrupted the
132 // user
133 private long mInterruptionTimeMs;
134
Gus Prevas7306b902018-12-11 10:57:06 -0500135 // The most recent time the notification made noise or buzzed the device, or -1 if it did not.
136 private long mLastAudiblyAlertedMs;
137
Chris Wrena3446562014-06-03 18:11:47 -0400138 // Is this record an update of an old record?
139 public boolean isUpdate;
Chris Wren54bbef42014-07-09 18:37:56 -0400140 private int mPackagePriority;
Chris Wrena3446562014-06-03 18:11:47 -0400141
Chris Wren1031c972014-07-23 13:11:45 +0000142 private int mAuthoritativeRank;
Christoph Studercd4adf82014-08-19 17:50:49 +0200143 private String mGlobalSortKey;
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400144 private int mPackageVisibility;
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400145 private int mSystemImportance = IMPORTANCE_UNSPECIFIED;
146 private int mAssistantImportance = IMPORTANCE_UNSPECIFIED;
Chris Wren47633422016-01-22 09:56:59 -0500147 private int mImportance = IMPORTANCE_UNSPECIFIED;
Alex Mang730d9492019-12-03 18:06:09 -0800148 private float mRankingScore = 0f;
Brad Stenning9a8b2c82018-08-03 14:14:26 -0700149 // Field used in global sort key to bypass normal notifications
150 private int mCriticality = CriticalNotificationExtractor.NORMAL;
Will Brockman934b8e32019-03-08 11:14:45 -0500151 // A MetricsEvent.NotificationImportanceExplanation, tracking source of mImportance.
152 private int mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN;
153 // A MetricsEvent.NotificationImportanceExplanation for initial importance.
154 private int mInitialImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN;
Chris Wren1031c972014-07-23 13:11:45 +0000155
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500156 private int mSuppressedVisualEffects = 0;
Julia Reynoldsef37f282016-02-12 09:11:27 -0500157 private String mUserExplanation;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000158 private boolean mPreChannelsNotification = true;
Julia Reynolds0c299d42016-11-15 14:37:04 -0500159 private Uri mSound;
160 private long[] mVibration;
161 private AudioAttributes mAttributes;
Julia Reynolds924eed12017-01-19 09:52:07 -0500162 private NotificationChannel mChannel;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500163 private ArrayList<String> mPeopleOverride;
164 private ArrayList<SnoozeCriterion> mSnoozeCriteria;
Julia Reynolds924eed12017-01-19 09:52:07 -0500165 private boolean mShowBadge;
Julia Reynolds4509ce72019-01-31 13:12:43 -0500166 private boolean mAllowBubble;
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500167 private Light mLight;
Danning Chen10326cf2020-01-16 13:29:13 -0800168 private boolean mIsNotConversationOverride;
Julia Reynoldsd61bdf12020-02-25 12:25:07 -0500169 private ShortcutInfo mShortcutInfo;
Gustav Sennton1463d832018-11-06 16:12:48 +0000170 /**
171 * This list contains system generated smart actions from NAS, app-generated smart actions are
Gustav Sennton005d7a02019-01-04 13:41:32 +0000172 * stored in Notification.actions with isContextual() set to true.
Gustav Sennton1463d832018-11-06 16:12:48 +0000173 */
174 private ArrayList<Notification.Action> mSystemGeneratedSmartActions;
Tony Makc9acf672018-07-20 13:58:24 +0200175 private ArrayList<CharSequence> mSmartReplies;
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500176
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400177 private final List<Adjustment> mAdjustments;
Jan Althaus367eb8c2019-05-23 11:31:42 +0200178 private String mAdjustmentIssuer;
Julia Reynolds503ed942017-10-04 16:04:56 -0400179 private final NotificationStats mStats;
180 private int mUserSentiment;
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500181 private boolean mIsInterruptive;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400182 private boolean mTextChanged;
183 private boolean mRecordedInterruption;
Kenny Guy23991102018-04-05 21:18:38 +0100184 private int mNumberOfSmartRepliesAdded;
Gustav Senntond25a64d2018-12-07 10:58:39 +0000185 private int mNumberOfSmartActionsAdded;
186 private boolean mSuggestionsGeneratedByAssistant;
Milo Sredkov13d88112019-02-01 12:23:24 +0000187 private boolean mEditChoicesBeforeSending;
Kenny Guy23991102018-04-05 21:18:38 +0100188 private boolean mHasSeenSmartReplies;
Mady Mellor13f9bc82020-03-24 19:09:28 -0700189 private boolean mFlagBubbleRemoved;
Julia Reynolds65031622020-02-27 09:11:25 -0500190 private boolean mPostSilently;
Julia Reynoldsbc23c7e2020-05-13 18:16:32 -0400191 private boolean mHasSentValidMsg;
192 private boolean mAppDemotedFromConvo;
Julia Reynolds4f73a7f2020-05-27 16:10:11 -0400193 private boolean mPkgAllowedAsConvo;
Rohan Shah590e1b22018-04-10 23:48:47 -0400194 /**
195 * Whether this notification (and its channels) should be considered user locked. Used in
196 * conjunction with user sentiment calculation.
197 */
198 private boolean mIsAppImportanceLocked;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600199 private ArraySet<Uri> mGrantableUris;
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400200
Julia Reynolds924eed12017-01-19 09:52:07 -0500201 public NotificationRecord(Context context, StatusBarNotification sbn,
Rohan Shah590e1b22018-04-10 23:48:47 -0400202 NotificationChannel channel) {
Chris Wren333a61c2014-05-28 16:40:57 -0400203 this.sbn = sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600204 mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class)
205 .getPackageTargetSdkVersion(sbn.getPackageName());
Julia Reynolds218871e2018-06-13 10:45:21 -0400206 mAm = ActivityManager.getService();
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700207 mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
Christoph Studer365e4c32014-09-18 20:35:36 +0200208 mOriginalFlags = sbn.getNotification().flags;
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200209 mRankingTimeMs = calculateRankingTimeMs(0L);
Chris Wren640e3872015-04-21 13:23:18 -0400210 mCreationTimeMs = sbn.getPostTime();
Chris Wren6650e572015-05-15 17:19:25 -0400211 mUpdateTimeMs = mCreationTimeMs;
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400212 mInterruptionTimeMs = mCreationTimeMs;
Chris Wrenbdf33762015-12-04 15:50:51 -0500213 mContext = context;
Chris Wrencdee8cd2016-01-25 17:10:30 -0500214 stats = new NotificationUsageStats.SingleNotificationStats();
Julia Reynolds924eed12017-01-19 09:52:07 -0500215 mChannel = channel;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000216 mPreChannelsNotification = isPreChannelsNotification();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500217 mSound = calculateSound();
218 mVibration = calculateVibration();
219 mAttributes = calculateAttributes();
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400220 mImportance = calculateInitialImportance();
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500221 mLight = calculateLights();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400222 mAdjustments = new ArrayList<>();
Julia Reynolds503ed942017-10-04 16:04:56 -0400223 mStats = new NotificationStats();
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500224 calculateUserSentiment();
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600225 calculateGrantableUris();
Chris Wrenbdf33762015-12-04 15:50:51 -0500226 }
227
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000228 private boolean isPreChannelsNotification() {
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600229 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) {
230 if (mTargetSdkVersion < Build.VERSION_CODES.O) {
231 return true;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000232 }
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000233 }
234 return false;
235 }
236
Julia Reynolds0c299d42016-11-15 14:37:04 -0500237 private Uri calculateSound() {
Julia Reynolds24edc002020-01-29 16:35:32 -0500238 final Notification n = getSbn().getNotification();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500239
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700240 // No notification sounds on tv
241 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
242 return null;
243 }
244
Julia Reynolds924eed12017-01-19 09:52:07 -0500245 Uri sound = mChannel.getSound();
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000246 if (mPreChannelsNotification && (getChannel().getUserLockedFields()
Julia Reynolds0c299d42016-11-15 14:37:04 -0500247 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
248
249 final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0;
250 if (useDefaultSound) {
251 sound = Settings.System.DEFAULT_NOTIFICATION_URI;
Julia Reynoldsb9e712e2017-04-17 10:31:03 -0400252 } else {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500253 sound = n.sound;
254 }
255 }
256 return sound;
257 }
258
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500259 private Light calculateLights() {
260 int defaultLightColor = mContext.getResources().getColor(
261 com.android.internal.R.color.config_defaultNotificationColor);
262 int defaultLightOn = mContext.getResources().getInteger(
263 com.android.internal.R.integer.config_defaultNotificationLedOn);
264 int defaultLightOff = mContext.getResources().getInteger(
265 com.android.internal.R.integer.config_defaultNotificationLedOff);
266
Julia Reynolds529e3322017-02-06 08:33:01 -0500267 int channelLightColor = getChannel().getLightColor() != 0 ? getChannel().getLightColor()
268 : defaultLightColor;
269 Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500270 defaultLightOn, defaultLightOff) : null;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000271 if (mPreChannelsNotification
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500272 && (getChannel().getUserLockedFields()
273 & NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
Julia Reynolds24edc002020-01-29 16:35:32 -0500274 final Notification notification = getSbn().getNotification();
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500275 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
276 light = new Light(notification.ledARGB, notification.ledOnMS,
277 notification.ledOffMS);
278 if ((notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
279 light = new Light(defaultLightColor, defaultLightOn,
280 defaultLightOff);
281 }
282 } else {
283 light = null;
284 }
285 }
286 return light;
287 }
288
Julia Reynolds0c299d42016-11-15 14:37:04 -0500289 private long[] calculateVibration() {
290 long[] vibration;
291 final long[] defaultVibration = NotificationManagerService.getLongArray(
292 mContext.getResources(),
293 com.android.internal.R.array.config_defaultNotificationVibePattern,
294 NotificationManagerService.VIBRATE_PATTERN_MAXLEN,
295 NotificationManagerService.DEFAULT_VIBRATE_PATTERN);
296 if (getChannel().shouldVibrate()) {
Julia Reynoldsf57de462016-11-23 11:31:46 -0500297 vibration = getChannel().getVibrationPattern() == null
298 ? defaultVibration : getChannel().getVibrationPattern();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500299 } else {
300 vibration = null;
301 }
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000302 if (mPreChannelsNotification
Julia Reynolds0c299d42016-11-15 14:37:04 -0500303 && (getChannel().getUserLockedFields()
304 & NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
Julia Reynolds24edc002020-01-29 16:35:32 -0500305 final Notification notification = getSbn().getNotification();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500306 final boolean useDefaultVibrate =
307 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
308 if (useDefaultVibrate) {
309 vibration = defaultVibration;
310 } else {
311 vibration = notification.vibrate;
312 }
313 }
314 return vibration;
315 }
316
317 private AudioAttributes calculateAttributes() {
Julia Reynolds24edc002020-01-29 16:35:32 -0500318 final Notification n = getSbn().getNotification();
Julia Reynolds619a69f2017-01-27 15:11:38 -0500319 AudioAttributes attributes = getChannel().getAudioAttributes();
320 if (attributes == null) {
321 attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
322 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500323
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000324 if (mPreChannelsNotification
Julia Reynolds619a69f2017-01-27 15:11:38 -0500325 && (getChannel().getUserLockedFields()
326 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
327 if (n.audioAttributes != null) {
328 // prefer audio attributes to stream type
329 attributes = n.audioAttributes;
330 } else if (n.audioStreamType >= 0
331 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
332 // the stream type is valid, use it
333 attributes = new AudioAttributes.Builder()
334 .setInternalLegacyStreamType(n.audioStreamType)
335 .build();
336 } else if (n.audioStreamType != AudioSystem.STREAM_DEFAULT) {
337 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
338 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500339 }
340 return attributes;
341 }
342
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400343 private int calculateInitialImportance() {
Julia Reynolds24edc002020-01-29 16:35:32 -0500344 final Notification n = getSbn().getNotification();
Will Brockman934b8e32019-03-08 11:14:45 -0500345 int importance = getChannel().getImportance(); // Post-channels notifications use this
346 mInitialImportanceExplanationCode = getChannel().hasUserSetImportance()
347 ? MetricsEvent.IMPORTANCE_EXPLANATION_USER
348 : MetricsEvent.IMPORTANCE_EXPLANATION_APP;
Chris Wrenbdf33762015-12-04 15:50:51 -0500349
Will Brockman934b8e32019-03-08 11:14:45 -0500350 // Migrate notification priority flag to a priority value.
Chris Wrenbdf33762015-12-04 15:50:51 -0500351 if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) {
352 n.priority = Notification.PRIORITY_MAX;
353 }
354
Will Brockman934b8e32019-03-08 11:14:45 -0500355 // Convert priority value to an importance value, used only for pre-channels notifications.
356 int requestedImportance = IMPORTANCE_DEFAULT;
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500357 n.priority = NotificationManagerService.clamp(n.priority, Notification.PRIORITY_MIN,
358 Notification.PRIORITY_MAX);
Chris Wrenbdf33762015-12-04 15:50:51 -0500359 switch (n.priority) {
360 case Notification.PRIORITY_MIN:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500361 requestedImportance = IMPORTANCE_MIN;
Julia Reynoldsf0f629f2016-02-25 09:34:04 -0500362 break;
Chris Wrenbdf33762015-12-04 15:50:51 -0500363 case Notification.PRIORITY_LOW:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500364 requestedImportance = IMPORTANCE_LOW;
Chris Wrenbdf33762015-12-04 15:50:51 -0500365 break;
366 case Notification.PRIORITY_DEFAULT:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500367 requestedImportance = IMPORTANCE_DEFAULT;
Chris Wrenbdf33762015-12-04 15:50:51 -0500368 break;
369 case Notification.PRIORITY_HIGH:
Chris Wrenbdf33762015-12-04 15:50:51 -0500370 case Notification.PRIORITY_MAX:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500371 requestedImportance = IMPORTANCE_HIGH;
Chris Wrenbdf33762015-12-04 15:50:51 -0500372 break;
373 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500374 stats.requestedImportance = requestedImportance;
kittychou(27880)fd213fb2020-06-11 15:03:55 +0800375 stats.isNoisy = mSound != null || mVibration != null
376 ||(n.defaults & Notification.DEFAULT_LIGHTS) != 0;
Chris Wrenbdf33762015-12-04 15:50:51 -0500377
Will Brockman934b8e32019-03-08 11:14:45 -0500378 // For pre-channels notifications, apply system overrides and then use requestedImportance
379 // as importance.
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000380 if (mPreChannelsNotification
Julia Reynoldsa917a112017-03-21 11:09:14 -0400381 && (importance == IMPORTANCE_UNSPECIFIED
Will Brockman934b8e32019-03-08 11:14:45 -0500382 || (!getChannel().hasUserSetImportance()))) {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500383 if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) {
384 requestedImportance = IMPORTANCE_LOW;
Julia Reynolds83fa1072016-02-17 09:10:19 -0500385 }
Julia Reynolds83fa1072016-02-17 09:10:19 -0500386
Julia Reynolds0c299d42016-11-15 14:37:04 -0500387 if (stats.isNoisy) {
388 if (requestedImportance < IMPORTANCE_DEFAULT) {
389 requestedImportance = IMPORTANCE_DEFAULT;
390 }
391 }
392
393 if (n.fullScreenIntent != null) {
394 requestedImportance = IMPORTANCE_HIGH;
395 }
396 importance = requestedImportance;
Will Brockman934b8e32019-03-08 11:14:45 -0500397 mInitialImportanceExplanationCode =
398 MetricsEvent.IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS;
Chris Wrenbdf33762015-12-04 15:50:51 -0500399 }
400
Chris Wrencdee8cd2016-01-25 17:10:30 -0500401 stats.naturalImportance = importance;
Chris Wrenbdf33762015-12-04 15:50:51 -0500402 return importance;
Chris Wren333a61c2014-05-28 16:40:57 -0400403 }
404
405 // copy any notes that the ranking system may have made before the update
406 public void copyRankingInformation(NotificationRecord previous) {
407 mContactAffinity = previous.mContactAffinity;
408 mRecentlyIntrusive = previous.mRecentlyIntrusive;
Chris Wren54bbef42014-07-09 18:37:56 -0400409 mPackagePriority = previous.mPackagePriority;
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400410 mPackageVisibility = previous.mPackageVisibility;
Chris Wren333a61c2014-05-28 16:40:57 -0400411 mIntercept = previous.mIntercept;
Beverly5a20a5e2018-03-06 15:02:44 -0500412 mHidden = previous.mHidden;
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200413 mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
Chris Wren640e3872015-04-21 13:23:18 -0400414 mCreationTimeMs = previous.mCreationTimeMs;
Chris Wren6650e572015-05-15 17:19:25 -0400415 mVisibleSinceMs = previous.mVisibleSinceMs;
Julia Reynolds24edc002020-01-29 16:35:32 -0500416 if (previous.getSbn().getOverrideGroupKey() != null && !getSbn().isAppGroup()) {
417 getSbn().setOverrideGroupKey(previous.getSbn().getOverrideGroupKey());
Chris Wren8a1638f2016-05-02 16:19:14 -0400418 }
Chris Wren1f602dc2016-04-11 10:33:46 -0400419 // Don't copy importance information or mGlobalSortKey, recompute them.
Chris Wren333a61c2014-05-28 16:40:57 -0400420 }
421
Julia Reynolds24edc002020-01-29 16:35:32 -0500422 public Notification getNotification() { return getSbn().getNotification(); }
423 public int getFlags() { return getSbn().getNotification().flags; }
424 public UserHandle getUser() { return getSbn().getUser(); }
425 public String getKey() { return getSbn().getKey(); }
Chris Wrenda4bd202014-09-04 15:53:52 -0400426 /** @deprecated Use {@link #getUser()} instead. */
Julia Reynolds24edc002020-01-29 16:35:32 -0500427 public int getUserId() { return getSbn().getUserId(); }
428 public int getUid() { return getSbn().getUid(); }
Chris Wren333a61c2014-05-28 16:40:57 -0400429
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800430 void dump(ProtoOutputStream proto, long fieldId, boolean redact, int state) {
431 final long token = proto.start(fieldId);
432
Julia Reynolds24edc002020-01-29 16:35:32 -0500433 proto.write(NotificationRecordProto.KEY, getSbn().getKey());
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800434 proto.write(NotificationRecordProto.STATE, state);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500435 if (getChannel() != null) {
436 proto.write(NotificationRecordProto.CHANNEL_ID, getChannel().getId());
437 }
438 proto.write(NotificationRecordProto.CAN_SHOW_LIGHT, getLight() != null);
439 proto.write(NotificationRecordProto.CAN_VIBRATE, getVibration() != null);
Julia Reynolds24edc002020-01-29 16:35:32 -0500440 proto.write(NotificationRecordProto.FLAGS, getSbn().getNotification().flags);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500441 proto.write(NotificationRecordProto.GROUP_KEY, getGroupKey());
442 proto.write(NotificationRecordProto.IMPORTANCE, getImportance());
443 if (getSound() != null) {
444 proto.write(NotificationRecordProto.SOUND, getSound().toString());
445 }
446 if (getAudioAttributes() != null) {
Jeffrey Huangcb782852019-12-05 11:28:11 -0800447 getAudioAttributes().dumpDebug(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500448 }
Julia Reynolds24edc002020-01-29 16:35:32 -0500449 proto.write(NotificationRecordProto.PACKAGE, getSbn().getPackageName());
450 proto.write(NotificationRecordProto.DELEGATE_PACKAGE, getSbn().getOpPkg());
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800451
452 proto.end(token);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500453 }
454
Dan Sandler0a2308e2017-05-30 19:50:42 -0400455 String formatRemoteViews(RemoteViews rv) {
456 if (rv == null) return "null";
457 return String.format("%s/0x%08x (%d bytes): %s",
458 rv.getPackage(), rv.getLayoutId(), rv.estimateMemoryUsage(), rv.toString());
459 }
460
Dan Sandlera1770312015-07-10 13:59:29 -0400461 void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
Julia Reynolds24edc002020-01-29 16:35:32 -0500462 final Notification notification = getSbn().getNotification();
Chris Wren333a61c2014-05-28 16:40:57 -0400463 pw.println(prefix + this);
Dan Sandler0a2308e2017-05-30 19:50:42 -0400464 prefix = prefix + " ";
Julia Reynolds24edc002020-01-29 16:35:32 -0500465 pw.println(prefix + "uid=" + getSbn().getUid() + " userId=" + getSbn().getUserId());
466 pw.println(prefix + "opPkg=" + getSbn().getOpPkg());
Julia Reynoldsc4ced652019-07-10 12:41:55 -0400467 pw.println(prefix + "icon=" + notification.getSmallIcon());
Julia Reynolds4db59552017-06-30 13:34:01 -0400468 pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400469 pw.println(prefix + "pri=" + notification.priority);
Julia Reynolds24edc002020-01-29 16:35:32 -0500470 pw.println(prefix + "key=" + getSbn().getKey());
Julia Reynolds503ed942017-10-04 16:04:56 -0400471 pw.println(prefix + "seen=" + mStats.hasSeen());
Julia Reynoldsa917a112017-03-21 11:09:14 -0400472 pw.println(prefix + "groupKey=" + getGroupKey());
473 pw.println(prefix + "fullscreenIntent=" + notification.fullScreenIntent);
474 pw.println(prefix + "contentIntent=" + notification.contentIntent);
475 pw.println(prefix + "deleteIntent=" + notification.deleteIntent);
Aaron Heuckrothb4d6aa72018-07-02 14:58:33 -0400476 pw.println(prefix + "number=" + notification.number);
477 pw.println(prefix + "groupAlertBehavior=" + notification.getGroupAlertBehavior());
Julia Reynolds434a2922020-01-21 13:33:59 -0500478 pw.println(prefix + "when=" + notification.when);
Dan Sandler0b4ceb32017-03-29 14:13:55 -0400479
480 pw.print(prefix + "tickerText=");
481 if (!TextUtils.isEmpty(notification.tickerText)) {
482 final String ticker = notification.tickerText.toString();
483 if (redact) {
484 // if the string is long enough, we allow ourselves a few bytes for debugging
485 pw.print(ticker.length() > 16 ? ticker.substring(0,8) : "");
486 pw.println("...");
487 } else {
488 pw.println(ticker);
489 }
490 } else {
491 pw.println("null");
492 }
Dan Sandler0a2308e2017-05-30 19:50:42 -0400493 pw.println(prefix + "contentView=" + formatRemoteViews(notification.contentView));
494 pw.println(prefix + "bigContentView=" + formatRemoteViews(notification.bigContentView));
495 pw.println(prefix + "headsUpContentView="
496 + formatRemoteViews(notification.headsUpContentView));
497 pw.print(prefix + String.format("color=0x%08x", notification.color));
Julia Reynoldsbad42972017-04-25 13:52:49 -0400498 pw.println(prefix + "timeout="
499 + TimeUtils.formatForLogging(notification.getTimeoutAfter()));
Chris Wren333a61c2014-05-28 16:40:57 -0400500 if (notification.actions != null && notification.actions.length > 0) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400501 pw.println(prefix + "actions={");
Chris Wren333a61c2014-05-28 16:40:57 -0400502 final int N = notification.actions.length;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500503 for (int i = 0; i < N; i++) {
Chris Wren333a61c2014-05-28 16:40:57 -0400504 final Notification.Action action = notification.actions[i];
Chris Wren1ac52a92016-02-24 14:54:52 -0500505 if (action != null) {
506 pw.println(String.format("%s [%d] \"%s\" -> %s",
507 prefix,
508 i,
509 action.title,
510 action.actionIntent == null ? "null" : action.actionIntent.toString()
511 ));
512 }
Chris Wren333a61c2014-05-28 16:40:57 -0400513 }
514 pw.println(prefix + " }");
515 }
516 if (notification.extras != null && notification.extras.size() > 0) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400517 pw.println(prefix + "extras={");
Chris Wren333a61c2014-05-28 16:40:57 -0400518 for (String key : notification.extras.keySet()) {
519 pw.print(prefix + " " + key + "=");
520 Object val = notification.extras.get(key);
521 if (val == null) {
522 pw.println("null");
523 } else {
524 pw.print(val.getClass().getSimpleName());
Dan Sandlera1770312015-07-10 13:59:29 -0400525 if (redact && (val instanceof CharSequence || val instanceof String)) {
Chris Wren333a61c2014-05-28 16:40:57 -0400526 // redact contents from bugreports
527 } else if (val instanceof Bitmap) {
528 pw.print(String.format(" (%dx%d)",
529 ((Bitmap) val).getWidth(),
530 ((Bitmap) val).getHeight()));
531 } else if (val.getClass().isArray()) {
532 final int N = Array.getLength(val);
Dan Sandlera1770312015-07-10 13:59:29 -0400533 pw.print(" (" + N + ")");
534 if (!redact) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500535 for (int j = 0; j < N; j++) {
Dan Sandlera1770312015-07-10 13:59:29 -0400536 pw.println();
537 pw.print(String.format("%s [%d] %s",
538 prefix, j, String.valueOf(Array.get(val, j))));
539 }
540 }
Chris Wren333a61c2014-05-28 16:40:57 -0400541 } else {
542 pw.print(" (" + String.valueOf(val) + ")");
543 }
544 pw.println();
545 }
546 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400547 pw.println(prefix + "}");
Chris Wren333a61c2014-05-28 16:40:57 -0400548 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400549 pw.println(prefix + "stats=" + stats.toString());
550 pw.println(prefix + "mContactAffinity=" + mContactAffinity);
551 pw.println(prefix + "mRecentlyIntrusive=" + mRecentlyIntrusive);
552 pw.println(prefix + "mPackagePriority=" + mPackagePriority);
553 pw.println(prefix + "mPackageVisibility=" + mPackageVisibility);
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400554 pw.println(prefix + "mSystemImportance="
555 + NotificationListenerService.Ranking.importanceToString(mSystemImportance));
556 pw.println(prefix + "mAsstImportance="
557 + NotificationListenerService.Ranking.importanceToString(mAssistantImportance));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400558 pw.println(prefix + "mImportance="
Chris Wrenbdf33762015-12-04 15:50:51 -0500559 + NotificationListenerService.Ranking.importanceToString(mImportance));
Will Brockman934b8e32019-03-08 11:14:45 -0500560 pw.println(prefix + "mImportanceExplanation=" + getImportanceExplanation());
Rohan Shah590e1b22018-04-10 23:48:47 -0400561 pw.println(prefix + "mIsAppImportanceLocked=" + mIsAppImportanceLocked);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400562 pw.println(prefix + "mIntercept=" + mIntercept);
Beverly5a20a5e2018-03-06 15:02:44 -0500563 pw.println(prefix + "mHidden==" + mHidden);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400564 pw.println(prefix + "mGlobalSortKey=" + mGlobalSortKey);
565 pw.println(prefix + "mRankingTimeMs=" + mRankingTimeMs);
566 pw.println(prefix + "mCreationTimeMs=" + mCreationTimeMs);
567 pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
568 pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400569 pw.println(prefix + "mInterruptionTimeMs=" + mInterruptionTimeMs);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400570 pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000571 if (mPreChannelsNotification) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400572 pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500573 notification.defaults, notification.flags));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400574 pw.println(prefix + "n.sound=" + notification.sound);
575 pw.println(prefix + "n.audioStreamType=" + notification.audioStreamType);
576 pw.println(prefix + "n.audioAttributes=" + notification.audioAttributes);
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500577 pw.println(prefix + String.format(" led=0x%08x onMs=%d offMs=%d",
578 notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400579 pw.println(prefix + "vibrate=" + Arrays.toString(notification.vibrate));
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500580 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400581 pw.println(prefix + "mSound= " + mSound);
582 pw.println(prefix + "mVibration= " + mVibration);
583 pw.println(prefix + "mAttributes= " + mAttributes);
584 pw.println(prefix + "mLight= " + mLight);
585 pw.println(prefix + "mShowBadge=" + mShowBadge);
Julia Reynolds4db59552017-06-30 13:34:01 -0400586 pw.println(prefix + "mColorized=" + notification.isColorized());
Mady Mellore96377e2020-04-07 15:12:48 -0700587 pw.println(prefix + "mAllowBubble=" + mAllowBubble);
588 pw.println(prefix + "isBubble=" + notification.isBubbleNotification());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500589 pw.println(prefix + "mIsInterruptive=" + mIsInterruptive);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400590 pw.println(prefix + "effectiveNotificationChannel=" + getChannel());
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500591 if (getPeopleOverride() != null) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400592 pw.println(prefix + "overridePeople= " + TextUtils.join(",", getPeopleOverride()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500593 }
594 if (getSnoozeCriteria() != null) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400595 pw.println(prefix + "snoozeCriteria=" + TextUtils.join(",", getSnoozeCriteria()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500596 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400597 pw.println(prefix + "mAdjustments=" + mAdjustments);
Julia Reynoldsfa273072020-04-14 15:31:21 -0400598 pw.println(prefix + "shortcut=" + notification.getShortcutId()
599 + " found valid? " + (mShortcutInfo != null));
Chris Wren333a61c2014-05-28 16:40:57 -0400600 }
601
Chris Wren333a61c2014-05-28 16:40:57 -0400602 @Override
603 public final String toString() {
604 return String.format(
Julia Reynolds85769912016-10-25 09:08:57 -0400605 "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s importance=%d key=%s" +
Julia Reynolds34523cd2019-07-02 10:13:29 -0400606 ": %s)",
Chris Wren333a61c2014-05-28 16:40:57 -0400607 System.identityHashCode(this),
Julia Reynolds24edc002020-01-29 16:35:32 -0500608 this.getSbn().getPackageName(), this.getSbn().getUser(), this.getSbn().getId(),
609 this.getSbn().getTag(), this.mImportance, this.getSbn().getKey(),
610 this.getSbn().getNotification());
Chris Wren333a61c2014-05-28 16:40:57 -0400611 }
612
Julia Reynolds27c0a962018-12-10 12:37:28 -0500613 public boolean hasAdjustment(String key) {
614 synchronized (mAdjustments) {
615 for (Adjustment adjustment : mAdjustments) {
616 if (adjustment.getSignals().containsKey(key)) {
617 return true;
618 }
619 }
620 }
621 return false;
622 }
623
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400624 public void addAdjustment(Adjustment adjustment) {
625 synchronized (mAdjustments) {
626 mAdjustments.add(adjustment);
627 }
628 }
629
630 public void applyAdjustments() {
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400631 long now = System.currentTimeMillis();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400632 synchronized (mAdjustments) {
633 for (Adjustment adjustment: mAdjustments) {
634 Bundle signals = adjustment.getSignals();
635 if (signals.containsKey(Adjustment.KEY_PEOPLE)) {
636 final ArrayList<String> people =
637 adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
638 setPeopleOverride(people);
639 }
640 if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) {
641 final ArrayList<SnoozeCriterion> snoozeCriterionList =
642 adjustment.getSignals().getParcelableArrayList(
643 Adjustment.KEY_SNOOZE_CRITERIA);
644 setSnoozeCriteria(snoozeCriterionList);
645 }
646 if (signals.containsKey(Adjustment.KEY_GROUP_KEY)) {
647 final String groupOverrideKey =
648 adjustment.getSignals().getString(Adjustment.KEY_GROUP_KEY);
649 setOverrideGroupKey(groupOverrideKey);
650 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400651 if (signals.containsKey(Adjustment.KEY_USER_SENTIMENT)) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500652 // Only allow user sentiment update from assistant if user hasn't already
653 // expressed a preference for this channel
Rohan Shah590e1b22018-04-10 23:48:47 -0400654 if (!mIsAppImportanceLocked
655 && (getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500656 setUserSentiment(adjustment.getSignals().getInt(
657 Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEUTRAL));
658 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400659 }
Tony Maka4716992019-01-24 15:41:59 +0000660 if (signals.containsKey(Adjustment.KEY_CONTEXTUAL_ACTIONS)) {
Gustav Sennton1463d832018-11-06 16:12:48 +0000661 setSystemGeneratedSmartActions(
Tony Maka4716992019-01-24 15:41:59 +0000662 signals.getParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS));
Tony Mak628cb932018-06-19 18:30:41 +0100663 }
Tony Maka4716992019-01-24 15:41:59 +0000664 if (signals.containsKey(Adjustment.KEY_TEXT_REPLIES)) {
665 setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_TEXT_REPLIES));
Tony Makc9acf672018-07-20 13:58:24 +0200666 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400667 if (signals.containsKey(Adjustment.KEY_IMPORTANCE)) {
668 int importance = signals.getInt(Adjustment.KEY_IMPORTANCE);
669 importance = Math.max(IMPORTANCE_UNSPECIFIED, importance);
670 importance = Math.min(IMPORTANCE_HIGH, importance);
671 setAssistantImportance(importance);
672 }
Alex Mang730d9492019-12-03 18:06:09 -0800673 if (signals.containsKey(Adjustment.KEY_RANKING_SCORE)) {
674 mRankingScore = signals.getFloat(Adjustment.KEY_RANKING_SCORE);
675 }
Danning Chen10326cf2020-01-16 13:29:13 -0800676 if (signals.containsKey(Adjustment.KEY_NOT_CONVERSATION)) {
677 mIsNotConversationOverride = signals.getBoolean(
678 Adjustment.KEY_NOT_CONVERSATION);
679 }
Jan Althaus367eb8c2019-05-23 11:31:42 +0200680 if (!signals.isEmpty() && adjustment.getIssuer() != null) {
681 mAdjustmentIssuer = adjustment.getIssuer();
682 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400683 }
Will Brockmanb020b5e2019-01-25 10:37:30 -0500684 // We have now gotten all the information out of the adjustments and can forget them.
685 mAdjustments.clear();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400686 }
687 }
688
Will Brockman2b6959e2020-01-22 09:59:50 -0500689 String getAdjustmentIssuer() {
690 return mAdjustmentIssuer;
691 }
692
Rohan Shah590e1b22018-04-10 23:48:47 -0400693 public void setIsAppImportanceLocked(boolean isAppImportanceLocked) {
694 mIsAppImportanceLocked = isAppImportanceLocked;
695 calculateUserSentiment();
696 }
697
Chris Wren333a61c2014-05-28 16:40:57 -0400698 public void setContactAffinity(float contactAffinity) {
699 mContactAffinity = contactAffinity;
700 }
701
702 public float getContactAffinity() {
703 return mContactAffinity;
704 }
705
John Spurlock1d881a12015-03-18 19:21:54 -0400706 public void setRecentlyIntrusive(boolean recentlyIntrusive) {
Chris Wren333a61c2014-05-28 16:40:57 -0400707 mRecentlyIntrusive = recentlyIntrusive;
Julia Reynolds309d1c82017-05-03 16:00:20 -0400708 if (recentlyIntrusive) {
709 mLastIntrusive = System.currentTimeMillis();
710 }
Chris Wren333a61c2014-05-28 16:40:57 -0400711 }
712
713 public boolean isRecentlyIntrusive() {
714 return mRecentlyIntrusive;
715 }
716
Julia Reynolds309d1c82017-05-03 16:00:20 -0400717 public long getLastIntrusive() {
718 return mLastIntrusive;
719 }
720
Chris Wren54bbef42014-07-09 18:37:56 -0400721 public void setPackagePriority(int packagePriority) {
John Spurlock6ac5f8d2014-07-18 11:27:54 -0400722 mPackagePriority = packagePriority;
Chris Wren54bbef42014-07-09 18:37:56 -0400723 }
724
725 public int getPackagePriority() {
726 return mPackagePriority;
727 }
728
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400729 public void setPackageVisibilityOverride(int packageVisibility) {
730 mPackageVisibility = packageVisibility;
731 }
732
733 public int getPackageVisibilityOverride() {
734 return mPackageVisibility;
735 }
736
Julia Reynoldsef37f282016-02-12 09:11:27 -0500737 private String getUserExplanation() {
738 if (mUserExplanation == null) {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500739 mUserExplanation = mContext.getResources().getString(
740 com.android.internal.R.string.importance_from_user);
Chris Wrenbdf33762015-12-04 15:50:51 -0500741 }
Julia Reynoldsef37f282016-02-12 09:11:27 -0500742 return mUserExplanation;
Chris Wrenbdf33762015-12-04 15:50:51 -0500743 }
744
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400745 /**
746 * Sets the importance value the system thinks the record should have.
747 * e.g. bumping up foreground service notifications or people to people notifications.
748 */
749 public void setSystemImportance(int importance) {
750 mSystemImportance = importance;
Julia Reynolds27c0a962018-12-10 12:37:28 -0500751 // System importance is only changed in enqueue, so it's ok for us to calculate the
752 // importance directly instead of waiting for signal extractor.
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400753 calculateImportance();
Chris Wrenbdf33762015-12-04 15:50:51 -0500754 }
755
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400756 /**
757 * Sets the importance value the
758 * {@link android.service.notification.NotificationAssistantService} thinks the record should
759 * have.
760 */
761 public void setAssistantImportance(int importance) {
762 mAssistantImportance = importance;
Julia Reynolds27c0a962018-12-10 12:37:28 -0500763 // Unlike the system importance, the assistant importance can change on posted
764 // notifications, so don't calculateImportance() here, but wait for the signal extractors.
765 }
766
767 /**
768 * Returns the importance set by the assistant, or IMPORTANCE_UNSPECIFIED if the assistant
769 * hasn't set it.
770 */
771 public int getAssistantImportance() {
772 return mAssistantImportance;
Julia Reynolds5d25ee72015-11-20 15:38:20 -0500773 }
774
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400775 /**
Will Brockman934b8e32019-03-08 11:14:45 -0500776 * Recalculates the importance of the record after fields affecting importance have changed,
777 * and records an explanation.
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400778 */
779 protected void calculateImportance() {
780 mImportance = calculateInitialImportance();
Will Brockman934b8e32019-03-08 11:14:45 -0500781 mImportanceExplanationCode = mInitialImportanceExplanationCode;
782
783 // Consider Notification Assistant and system overrides to importance. If both, system wins.
Julia Reynolds27c0a962018-12-10 12:37:28 -0500784 if (!getChannel().hasUserSetImportance()
Julia Reynolds413ba842019-01-11 10:38:08 -0500785 && mAssistantImportance != IMPORTANCE_UNSPECIFIED
Julia Reynolds0c245002019-03-27 16:10:11 -0400786 && !getChannel().isImportanceLockedByOEM()
787 && !getChannel().isImportanceLockedByCriticalDeviceFunction()) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400788 mImportance = mAssistantImportance;
Will Brockman934b8e32019-03-08 11:14:45 -0500789 mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_ASST;
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400790 }
791 if (mSystemImportance != IMPORTANCE_UNSPECIFIED) {
792 mImportance = mSystemImportance;
Will Brockman934b8e32019-03-08 11:14:45 -0500793 mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM;
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400794 }
Chris Wrenbdf33762015-12-04 15:50:51 -0500795 }
796
797 public int getImportance() {
798 return mImportance;
799 }
800
Will Brockman2b6959e2020-01-22 09:59:50 -0500801 int getInitialImportance() {
802 return stats.naturalImportance;
803 }
804
Alex Mang730d9492019-12-03 18:06:09 -0800805 public float getRankingScore() {
806 return mRankingScore;
807 }
808
Will Brockman2b6959e2020-01-22 09:59:50 -0500809 int getImportanceExplanationCode() {
810 return mImportanceExplanationCode;
811 }
812
813 int getInitialImportanceExplanationCode() {
814 return mInitialImportanceExplanationCode;
815 }
816
Chris Wrenbdf33762015-12-04 15:50:51 -0500817 public CharSequence getImportanceExplanation() {
Will Brockman934b8e32019-03-08 11:14:45 -0500818 switch (mImportanceExplanationCode) {
819 case MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN:
820 return null;
821 case MetricsEvent.IMPORTANCE_EXPLANATION_APP:
822 case MetricsEvent.IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS:
823 return "app";
824 case MetricsEvent.IMPORTANCE_EXPLANATION_USER:
825 return "user";
826 case MetricsEvent.IMPORTANCE_EXPLANATION_ASST:
827 return "asst";
828 case MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM:
829 return "system";
830 }
831 return null;
Chris Wrenbdf33762015-12-04 15:50:51 -0500832 }
833
Chris Wren333a61c2014-05-28 16:40:57 -0400834 public boolean setIntercepted(boolean intercept) {
835 mIntercept = intercept;
836 return mIntercept;
837 }
838
Brad Stenning9a8b2c82018-08-03 14:14:26 -0700839 /**
840 * Set to affect global sort key.
841 *
842 * @param criticality used in a string based sort thus 0 is the most critical
843 */
844 public void setCriticality(int criticality) {
845 mCriticality = criticality;
846 }
847
848 public int getCriticality() {
849 return mCriticality;
850 }
851
Chris Wren333a61c2014-05-28 16:40:57 -0400852 public boolean isIntercepted() {
853 return mIntercept;
854 }
855
Julia Reynoldsd6730072019-01-04 12:52:52 -0500856 public boolean isNewEnoughForAlerting(long now) {
857 return getFreshnessMs(now) <= MAX_SOUND_DELAY_MS;
858 }
859
Beverly5a20a5e2018-03-06 15:02:44 -0500860 public void setHidden(boolean hidden) {
861 mHidden = hidden;
862 }
863
864 public boolean isHidden() {
865 return mHidden;
866 }
867
Julia Reynolds65031622020-02-27 09:11:25 -0500868 /**
869 * Override of all alerting information on the channel and notification. Used when notifications
870 * are reposted in response to direct user action and thus don't need to alert.
871 */
872 public void setPostSilently(boolean postSilently) {
873 mPostSilently = postSilently;
874 }
875
876 public boolean shouldPostSilently() {
877 return mPostSilently;
878 }
Beverly5a20a5e2018-03-06 15:02:44 -0500879
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500880 public void setSuppressedVisualEffects(int effects) {
881 mSuppressedVisualEffects = effects;
882 }
883
884 public int getSuppressedVisualEffects() {
885 return mSuppressedVisualEffects;
886 }
887
John Spurlock312d1d02014-07-08 10:24:57 -0400888 public boolean isCategory(String category) {
John Spurlockbfa5dc42014-07-28 23:30:45 -0400889 return Objects.equals(getNotification().category, category);
890 }
891
John Spurlockbfa5dc42014-07-28 23:30:45 -0400892 public boolean isAudioAttributesUsage(int usage) {
Julia Reynolds51eb78f82018-03-07 07:35:21 -0500893 return mAttributes != null && mAttributes.getUsage() == usage;
John Spurlock312d1d02014-07-08 10:24:57 -0400894 }
895
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200896 /**
897 * Returns the timestamp to use for time-based sorting in the ranker.
898 */
899 public long getRankingTimeMs() {
900 return mRankingTimeMs;
901 }
902
903 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400904 * @param now this current time in milliseconds.
905 * @returns the number of milliseconds since the most recent update, or the post time if none.
Chris Wren6650e572015-05-15 17:19:25 -0400906 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400907 public int getFreshnessMs(long now) {
908 return (int) (now - mUpdateTimeMs);
Chris Wren6650e572015-05-15 17:19:25 -0400909 }
910
911 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400912 * @param now this current time in milliseconds.
913 * @returns the number of milliseconds since the the first post, ignoring updates.
Chris Wren640e3872015-04-21 13:23:18 -0400914 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400915 public int getLifespanMs(long now) {
916 return (int) (now - mCreationTimeMs);
Chris Wren640e3872015-04-21 13:23:18 -0400917 }
918
919 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400920 * @param now this current time in milliseconds.
921 * @returns the number of milliseconds since the most recent visibility event, or 0 if never.
Chris Wren6650e572015-05-15 17:19:25 -0400922 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400923 public int getExposureMs(long now) {
924 return mVisibleSinceMs == 0 ? 0 : (int) (now - mVisibleSinceMs);
Chris Wren6650e572015-05-15 17:19:25 -0400925 }
926
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400927 public int getInterruptionMs(long now) {
928 return (int) (now - mInterruptionTimeMs);
929 }
930
Evan Lairdd04af512020-01-09 11:18:09 -0500931 public long getUpdateTimeMs() {
932 return mUpdateTimeMs;
933 }
934
Chris Wren6650e572015-05-15 17:19:25 -0400935 /**
936 * Set the visibility of the notification.
937 */
Will Brockmand3d49332020-02-10 19:43:03 -0500938 public void setVisibility(boolean visible, int rank, int count,
939 NotificationRecordLogger notificationRecordLogger) {
Chris Wren6650e572015-05-15 17:19:25 -0400940 final long now = System.currentTimeMillis();
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400941 mVisibleSinceMs = visible ? now : mVisibleSinceMs;
Chris Wren6650e572015-05-15 17:19:25 -0400942 stats.onVisibilityChanged(visible);
Chris Wren9eb5e102017-01-26 13:15:06 -0500943 MetricsLogger.action(getLogMaker(now)
944 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
945 .setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800946 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
947 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count));
Chris Wren9eb5e102017-01-26 13:15:06 -0500948 if (visible) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400949 setSeen();
Chris Wren9eb5e102017-01-26 13:15:06 -0500950 MetricsLogger.histogram(mContext, "note_freshness", getFreshnessMs(now));
951 }
Chris Wren6650e572015-05-15 17:19:25 -0400952 EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0,
Chris Wren9eb5e102017-01-26 13:15:06 -0500953 getLifespanMs(now),
954 getFreshnessMs(now),
Chris Wrend1dbc922015-06-19 17:51:16 -0400955 0, // exposure time
956 rank);
Will Brockmand3d49332020-02-10 19:43:03 -0500957 notificationRecordLogger.logNotificationVisibility(this, visible);
Chris Wren6650e572015-05-15 17:19:25 -0400958 }
959
960 /**
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200961 * @param previousRankingTimeMs for updated notifications, {@link #getRankingTimeMs()}
962 * of the previous notification record, 0 otherwise
963 */
964 private long calculateRankingTimeMs(long previousRankingTimeMs) {
965 Notification n = getNotification();
966 // Take developer provided 'when', unless it's in the future.
Julia Reynolds24edc002020-01-29 16:35:32 -0500967 if (n.when != 0 && n.when <= getSbn().getPostTime()) {
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200968 return n.when;
969 }
970 // If we've ranked a previous instance with a timestamp, inherit it. This case is
971 // important in order to have ranking stability for updating notifications.
972 if (previousRankingTimeMs > 0) {
973 return previousRankingTimeMs;
974 }
Julia Reynolds24edc002020-01-29 16:35:32 -0500975 return getSbn().getPostTime();
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200976 }
Chris Wren1031c972014-07-23 13:11:45 +0000977
Christoph Studercd4adf82014-08-19 17:50:49 +0200978 public void setGlobalSortKey(String globalSortKey) {
979 mGlobalSortKey = globalSortKey;
Chris Wren1031c972014-07-23 13:11:45 +0000980 }
981
Christoph Studercd4adf82014-08-19 17:50:49 +0200982 public String getGlobalSortKey() {
983 return mGlobalSortKey;
Chris Wren1031c972014-07-23 13:11:45 +0000984 }
985
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700986 /** Check if any of the listeners have marked this notification as seen by the user. */
987 public boolean isSeen() {
Julia Reynolds503ed942017-10-04 16:04:56 -0400988 return mStats.hasSeen();
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700989 }
990
991 /** Mark the notification as seen by the user. */
992 public void setSeen() {
Julia Reynolds503ed942017-10-04 16:04:56 -0400993 mStats.setSeen();
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400994 if (mTextChanged) {
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400995 setInterruptive(true);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400996 }
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700997 }
998
Chris Wren1031c972014-07-23 13:11:45 +0000999 public void setAuthoritativeRank(int authoritativeRank) {
1000 mAuthoritativeRank = authoritativeRank;
1001 }
1002
1003 public int getAuthoritativeRank() {
1004 return mAuthoritativeRank;
1005 }
1006
1007 public String getGroupKey() {
Julia Reynolds24edc002020-01-29 16:35:32 -05001008 return getSbn().getGroupKey();
Chris Wren1031c972014-07-23 13:11:45 +00001009 }
Chris Wren47633422016-01-22 09:56:59 -05001010
Chris Wrenb3921792017-06-01 13:34:46 -04001011 public void setOverrideGroupKey(String overrideGroupKey) {
Julia Reynolds24edc002020-01-29 16:35:32 -05001012 getSbn().setOverrideGroupKey(overrideGroupKey);
Chris Wrenb3921792017-06-01 13:34:46 -04001013 }
1014
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001015 public NotificationChannel getChannel() {
Julia Reynolds924eed12017-01-19 09:52:07 -05001016 return mChannel;
Julia Reynolds22f02b32016-12-01 15:05:13 -05001017 }
1018
Rohan Shah590e1b22018-04-10 23:48:47 -04001019 /**
Julia Reynoldsefcdff42018-08-09 09:42:56 -04001020 * @see PreferencesHelper#getIsAppImportanceLocked(String, int)
Rohan Shah590e1b22018-04-10 23:48:47 -04001021 */
1022 public boolean getIsAppImportanceLocked() {
1023 return mIsAppImportanceLocked;
1024 }
1025
Julia Reynolds924eed12017-01-19 09:52:07 -05001026 protected void updateNotificationChannel(NotificationChannel channel) {
1027 if (channel != null) {
1028 mChannel = channel;
Julia Reynolds22f02b32016-12-01 15:05:13 -05001029 calculateImportance();
Julia Reynoldsc65656a2018-02-12 09:55:14 -05001030 calculateUserSentiment();
Julia Reynolds22f02b32016-12-01 15:05:13 -05001031 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001032 }
Julia Reynolds0c299d42016-11-15 14:37:04 -05001033
Julia Reynolds924eed12017-01-19 09:52:07 -05001034 public void setShowBadge(boolean showBadge) {
1035 mShowBadge = showBadge;
1036 }
1037
Julia Reynolds4509ce72019-01-31 13:12:43 -05001038 public boolean canBubble() {
1039 return mAllowBubble;
1040 }
1041
1042 public void setAllowBubble(boolean allow) {
1043 mAllowBubble = allow;
1044 }
1045
Julia Reynolds924eed12017-01-19 09:52:07 -05001046 public boolean canShowBadge() {
1047 return mShowBadge;
1048 }
1049
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05001050 public Light getLight() {
1051 return mLight;
1052 }
1053
Julia Reynolds0c299d42016-11-15 14:37:04 -05001054 public Uri getSound() {
1055 return mSound;
1056 }
1057
1058 public long[] getVibration() {
1059 return mVibration;
1060 }
1061
1062 public AudioAttributes getAudioAttributes() {
1063 return mAttributes;
1064 }
Julia Reynolds22f02b32016-12-01 15:05:13 -05001065
1066 public ArrayList<String> getPeopleOverride() {
1067 return mPeopleOverride;
1068 }
1069
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001070 public void setInterruptive(boolean interruptive) {
1071 mIsInterruptive = interruptive;
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -04001072 final long now = System.currentTimeMillis();
1073 mInterruptionTimeMs = interruptive ? now : mInterruptionTimeMs;
1074
1075 if (interruptive) {
1076 MetricsLogger.action(getLogMaker()
1077 .setCategory(MetricsEvent.NOTIFICATION_INTERRUPTION)
1078 .setType(MetricsEvent.TYPE_OPEN)
1079 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS,
1080 getInterruptionMs(now)));
1081 MetricsLogger.histogram(mContext, "note_interruptive", getInterruptionMs(now));
1082 }
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001083 }
1084
Gus Prevasa3226492018-10-23 11:10:09 -04001085 public void setAudiblyAlerted(boolean audiblyAlerted) {
Gus Prevas7306b902018-12-11 10:57:06 -05001086 mLastAudiblyAlertedMs = audiblyAlerted ? System.currentTimeMillis() : -1;
Gus Prevasa3226492018-10-23 11:10:09 -04001087 }
1088
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001089 public void setTextChanged(boolean textChanged) {
1090 mTextChanged = textChanged;
1091 }
1092
1093 public void setRecordedInterruption(boolean recorded) {
1094 mRecordedInterruption = recorded;
1095 }
1096
1097 public boolean hasRecordedInterruption() {
1098 return mRecordedInterruption;
1099 }
1100
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001101 public boolean isInterruptive() {
1102 return mIsInterruptive;
1103 }
1104
Gus Prevas7306b902018-12-11 10:57:06 -05001105 /** Returns the time the notification audibly alerted the user. */
1106 public long getLastAudiblyAlertedMs() {
1107 return mLastAudiblyAlertedMs;
Gus Prevasa3226492018-10-23 11:10:09 -04001108 }
1109
Julia Reynolds22f02b32016-12-01 15:05:13 -05001110 protected void setPeopleOverride(ArrayList<String> people) {
1111 mPeopleOverride = people;
1112 }
1113
1114 public ArrayList<SnoozeCriterion> getSnoozeCriteria() {
1115 return mSnoozeCriteria;
1116 }
1117
1118 protected void setSnoozeCriteria(ArrayList<SnoozeCriterion> snoozeCriteria) {
1119 mSnoozeCriteria = snoozeCriteria;
1120 }
Chris Wren9eb5e102017-01-26 13:15:06 -05001121
Julia Reynoldsc65656a2018-02-12 09:55:14 -05001122 private void calculateUserSentiment() {
Rohan Shah590e1b22018-04-10 23:48:47 -04001123 if ((getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0
1124 || mIsAppImportanceLocked) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -05001125 mUserSentiment = USER_SENTIMENT_POSITIVE;
1126 }
1127 }
1128
Julia Reynolds503ed942017-10-04 16:04:56 -04001129 private void setUserSentiment(int userSentiment) {
1130 mUserSentiment = userSentiment;
1131 }
1132
1133 public int getUserSentiment() {
1134 return mUserSentiment;
1135 }
1136
1137 public NotificationStats getStats() {
1138 return mStats;
1139 }
1140
1141 public void recordExpanded() {
1142 mStats.setExpanded();
1143 }
1144
1145 public void recordDirectReplied() {
1146 mStats.setDirectReplied();
1147 }
1148
1149 public void recordDismissalSurface(@NotificationStats.DismissalSurface int surface) {
1150 mStats.setDismissalSurface(surface);
1151 }
1152
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04001153 public void recordDismissalSentiment(@NotificationStats.DismissalSentiment int sentiment) {
1154 mStats.setDismissalSentiment(sentiment);
1155 }
1156
Julia Reynolds503ed942017-10-04 16:04:56 -04001157 public void recordSnoozed() {
1158 mStats.setSnoozed();
1159 }
1160
1161 public void recordViewedSettings() {
1162 mStats.setViewedSettings();
1163 }
1164
Kenny Guy23991102018-04-05 21:18:38 +01001165 public void setNumSmartRepliesAdded(int noReplies) {
1166 mNumberOfSmartRepliesAdded = noReplies;
1167 }
1168
1169 public int getNumSmartRepliesAdded() {
1170 return mNumberOfSmartRepliesAdded;
1171 }
1172
Gustav Senntond25a64d2018-12-07 10:58:39 +00001173 public void setNumSmartActionsAdded(int noActions) {
1174 mNumberOfSmartActionsAdded = noActions;
1175 }
1176
1177 public int getNumSmartActionsAdded() {
1178 return mNumberOfSmartActionsAdded;
1179 }
1180
1181 public void setSuggestionsGeneratedByAssistant(boolean generatedByAssistant) {
1182 mSuggestionsGeneratedByAssistant = generatedByAssistant;
1183 }
1184
1185 public boolean getSuggestionsGeneratedByAssistant() {
1186 return mSuggestionsGeneratedByAssistant;
1187 }
1188
Milo Sredkov13d88112019-02-01 12:23:24 +00001189 public boolean getEditChoicesBeforeSending() {
1190 return mEditChoicesBeforeSending;
1191 }
1192
1193 public void setEditChoicesBeforeSending(boolean editChoicesBeforeSending) {
1194 mEditChoicesBeforeSending = editChoicesBeforeSending;
1195 }
1196
Kenny Guy23991102018-04-05 21:18:38 +01001197 public boolean hasSeenSmartReplies() {
1198 return mHasSeenSmartReplies;
1199 }
1200
1201 public void setSeenSmartReplies(boolean hasSeenSmartReplies) {
1202 mHasSeenSmartReplies = hasSeenSmartReplies;
1203 }
1204
Gustav Sennton44dc5882018-12-13 14:38:50 +00001205 /**
1206 * Returns whether this notification has been visible and expanded at the same time.
1207 */
1208 public boolean hasBeenVisiblyExpanded() {
1209 return stats.hasBeenVisiblyExpanded();
1210 }
1211
Mady Mellor13f9bc82020-03-24 19:09:28 -07001212 /**
1213 * When the bubble state on a notif changes due to user action (e.g. dismiss a bubble) then
1214 * this value is set until an update or bubble change event due to user action (e.g. create
1215 * bubble from sysui)
1216 **/
1217 public boolean isFlagBubbleRemoved() {
1218 return mFlagBubbleRemoved;
1219 }
1220
1221 public void setFlagBubbleRemoved(boolean flagBubbleRemoved) {
1222 mFlagBubbleRemoved = flagBubbleRemoved;
1223 }
1224
Gustav Sennton1463d832018-11-06 16:12:48 +00001225 public void setSystemGeneratedSmartActions(
1226 ArrayList<Notification.Action> systemGeneratedSmartActions) {
1227 mSystemGeneratedSmartActions = systemGeneratedSmartActions;
Tony Mak628cb932018-06-19 18:30:41 +01001228 }
1229
Gustav Sennton1463d832018-11-06 16:12:48 +00001230 public ArrayList<Notification.Action> getSystemGeneratedSmartActions() {
1231 return mSystemGeneratedSmartActions;
Tony Mak628cb932018-06-19 18:30:41 +01001232 }
1233
Tony Makc9acf672018-07-20 13:58:24 +02001234 public void setSmartReplies(ArrayList<CharSequence> smartReplies) {
1235 mSmartReplies = smartReplies;
1236 }
1237
1238 public ArrayList<CharSequence> getSmartReplies() {
1239 return mSmartReplies;
1240 }
1241
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001242 /**
Julia Reynolds95334132018-12-19 11:15:35 -05001243 * Returns whether this notification was posted by a secondary app
1244 */
1245 public boolean isProxied() {
Julia Reynolds24edc002020-01-29 16:35:32 -05001246 return !Objects.equals(getSbn().getPackageName(), getSbn().getOpPkg());
Julia Reynolds95334132018-12-19 11:15:35 -05001247 }
1248
1249 /**
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001250 * @return all {@link Uri} that should have permission granted to whoever
1251 * will be rendering it. This list has already been vetted to only
1252 * include {@link Uri} that the enqueuing app can grant.
1253 */
1254 public @Nullable ArraySet<Uri> getGrantableUris() {
1255 return mGrantableUris;
1256 }
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001257
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001258 /**
1259 * Collect all {@link Uri} that should have permission granted to whoever
1260 * will be rendering it.
1261 */
Julia Reynolds218871e2018-06-13 10:45:21 -04001262 protected void calculateGrantableUris() {
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001263 final Notification notification = getNotification();
Jeff Sharkey23b31182018-04-18 21:32:12 -06001264 notification.visitUris((uri) -> {
Julia Reynolds218871e2018-06-13 10:45:21 -04001265 visitGrantableUri(uri, false);
Jeff Sharkey23b31182018-04-18 21:32:12 -06001266 });
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001267
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001268 if (notification.getChannelId() != null) {
1269 NotificationChannel channel = getChannel();
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001270 if (channel != null) {
Julia Reynolds218871e2018-06-13 10:45:21 -04001271 visitGrantableUri(channel.getSound(), (channel.getUserLockedFields()
1272 & NotificationChannel.USER_LOCKED_SOUND) != 0);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001273 }
1274 }
1275 }
1276
1277 /**
1278 * Note the presence of a {@link Uri} that should have permission granted to
1279 * whoever will be rendering it.
1280 * <p>
1281 * If the enqueuing app has the ability to grant access, it will be added to
1282 * {@link #mGrantableUris}. Otherwise, this will either log or throw
1283 * {@link SecurityException} depending on target SDK of enqueuing app.
1284 */
Julia Reynolds218871e2018-06-13 10:45:21 -04001285 private void visitGrantableUri(Uri uri, boolean userOverriddenUri) {
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001286 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
1287
1288 // We can't grant Uri permissions from system
Julia Reynolds24edc002020-01-29 16:35:32 -05001289 final int sourceUid = getSbn().getUid();
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001290 if (sourceUid == android.os.Process.SYSTEM_UID) return;
1291
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001292 final long ident = Binder.clearCallingIdentity();
1293 try {
1294 // This will throw SecurityException if caller can't grant
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001295 mUgmInternal.checkGrantUriPermission(sourceUid, null,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001296 ContentProvider.getUriWithoutUserId(uri),
1297 Intent.FLAG_GRANT_READ_URI_PERMISSION,
1298 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
1299
1300 if (mGrantableUris == null) {
1301 mGrantableUris = new ArraySet<>();
1302 }
1303 mGrantableUris.add(uri);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001304 } catch (SecurityException e) {
Julia Reynolds218871e2018-06-13 10:45:21 -04001305 if (!userOverriddenUri) {
1306 if (mTargetSdkVersion >= Build.VERSION_CODES.P) {
1307 throw e;
1308 } else {
1309 Log.w(TAG, "Ignoring " + uri + " from " + sourceUid + ": " + e.getMessage());
1310 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001311 }
1312 } finally {
1313 Binder.restoreCallingIdentity(ident);
1314 }
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001315 }
1316
Chris Wren9eb5e102017-01-26 13:15:06 -05001317 public LogMaker getLogMaker(long now) {
Julia Reynolds24edc002020-01-29 16:35:32 -05001318 LogMaker lm = getSbn().getLogMaker()
Chris Wrenb3921792017-06-01 13:34:46 -04001319 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance)
Chris Wren9eb5e102017-01-26 13:15:06 -05001320 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now))
1321 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now))
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -04001322 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now))
1323 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS,
1324 getInterruptionMs(now));
Will Brockman934b8e32019-03-08 11:14:45 -05001325 // Record results of the calculateImportance() calculation if available.
1326 if (mImportanceExplanationCode != MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN) {
1327 lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION,
1328 mImportanceExplanationCode);
1329 // To avoid redundancy, we log the initial importance information only if it was
1330 // overridden.
1331 if (((mImportanceExplanationCode == MetricsEvent.IMPORTANCE_EXPLANATION_ASST)
1332 || (mImportanceExplanationCode == MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM))
1333 && (stats.naturalImportance != IMPORTANCE_UNSPECIFIED)) {
1334 // stats.naturalImportance is due to one of the 3 sources of initial importance.
1335 lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION,
1336 mInitialImportanceExplanationCode);
1337 lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL,
1338 stats.naturalImportance);
1339 }
Will Brockman605d61b2019-03-29 13:08:49 -04001340 }
1341 // Log Assistant override if present, whether or not importance calculation is complete.
1342 if (mAssistantImportance != IMPORTANCE_UNSPECIFIED) {
1343 lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST,
Will Brockman934b8e32019-03-08 11:14:45 -05001344 mAssistantImportance);
Will Brockman934b8e32019-03-08 11:14:45 -05001345 }
Jan Althaus367eb8c2019-05-23 11:31:42 +02001346 // Log the issuer of any adjustments that may have affected this notification. We only log
1347 // the hash here as NotificationItem events are frequent, and the number of NAS
1348 // implementations (and hence the chance of collisions) is low.
1349 if (mAdjustmentIssuer != null) {
1350 lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_ASSISTANT_SERVICE_HASH,
1351 mAdjustmentIssuer.hashCode());
1352 }
Will Brockman934b8e32019-03-08 11:14:45 -05001353 return lm;
Chris Wren9eb5e102017-01-26 13:15:06 -05001354 }
1355
1356 public LogMaker getLogMaker() {
1357 return getLogMaker(System.currentTimeMillis());
1358 }
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05001359
Julia Reynolds3dfdde02018-10-08 09:17:56 -04001360 public LogMaker getItemLogMaker() {
1361 return getLogMaker().setCategory(MetricsEvent.NOTIFICATION_ITEM);
1362 }
1363
Chris Wren6cbf57b2019-12-12 15:33:21 -05001364 public boolean hasUndecoratedRemoteView() {
1365 Notification notification = getNotification();
1366 Class<? extends Notification.Style> style = notification.getNotificationStyle();
1367 boolean hasDecoratedStyle = style != null
1368 && (Notification.DecoratedCustomViewStyle.class.equals(style)
1369 || Notification.DecoratedMediaCustomViewStyle.class.equals(style));
1370 boolean hasCustomRemoteView = notification.contentView != null
1371 || notification.bigContentView != null
1372 || notification.headsUpContentView != null;
1373 return hasCustomRemoteView && !hasDecoratedStyle;
1374 }
1375
Julia Reynoldsd61bdf12020-02-25 12:25:07 -05001376 public void setShortcutInfo(ShortcutInfo shortcutInfo) {
1377 mShortcutInfo = shortcutInfo;
1378 }
1379
Julia Reynolds138111f2020-02-26 11:17:39 -05001380 public ShortcutInfo getShortcutInfo() {
1381 return mShortcutInfo;
1382 }
1383
Julia Reynoldsbc23c7e2020-05-13 18:16:32 -04001384 public void setHasSentValidMsg(boolean hasSentValidMsg) {
1385 mHasSentValidMsg = hasSentValidMsg;
1386 }
1387
1388 public void userDemotedAppFromConvoSpace(boolean userDemoted) {
1389 mAppDemotedFromConvo = userDemoted;
1390 }
1391
Julia Reynolds4f73a7f2020-05-27 16:10:11 -04001392 public void setPkgAllowedAsConvo(boolean allowedAsConvo) {
1393 mPkgAllowedAsConvo = allowedAsConvo;
1394 }
1395
Julia Reynoldsd61bdf12020-02-25 12:25:07 -05001396 /**
1397 * Whether this notification is a conversation notification.
1398 */
Danning Chen10326cf2020-01-16 13:29:13 -08001399 public boolean isConversation() {
1400 Notification notification = getNotification();
Julia Reynolds4f73a7f2020-05-27 16:10:11 -04001401 // user kicked it out of convo space
1402 if (mChannel.isDemoted() || mAppDemotedFromConvo) {
Julia Reynoldsc76888d2020-05-04 15:36:09 -04001403 return false;
1404 }
Julia Reynolds4f73a7f2020-05-27 16:10:11 -04001405 // NAS kicked it out of notification space
Danning Chen10326cf2020-01-16 13:29:13 -08001406 if (mIsNotConversationOverride) {
1407 return false;
1408 }
Julia Reynolds4f73a7f2020-05-27 16:10:11 -04001409 if (!Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
1410 // some non-msgStyle notifs can temporarily appear in the conversation space if category
1411 // is right
1412 if (mPkgAllowedAsConvo && mTargetSdkVersion < Build.VERSION_CODES.R
1413 && Notification.CATEGORY_MESSAGE.equals(getNotification().category)) {
1414 return true;
1415 }
1416 return false;
1417 }
1418
Julia Reynoldsc76888d2020-05-04 15:36:09 -04001419 if (mTargetSdkVersion >= Build.VERSION_CODES.R
1420 && Notification.MessagingStyle.class.equals(notification.getNotificationStyle())
1421 && mShortcutInfo == null) {
1422 return false;
1423 }
Julia Reynoldsbc23c7e2020-05-13 18:16:32 -04001424 if (mHasSentValidMsg && mShortcutInfo == null) {
1425 return false;
1426 }
Danning Chen10326cf2020-01-16 13:29:13 -08001427 return true;
1428 }
1429
Julia Reynolds24edc002020-01-29 16:35:32 -05001430 StatusBarNotification getSbn() {
1431 return sbn;
1432 }
1433
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05001434 @VisibleForTesting
1435 static final class Light {
1436 public final int color;
1437 public final int onMs;
1438 public final int offMs;
1439
1440 public Light(int color, int onMs, int offMs) {
1441 this.color = color;
1442 this.onMs = onMs;
1443 this.offMs = offMs;
1444 }
1445
1446 @Override
1447 public boolean equals(Object o) {
1448 if (this == o) return true;
1449 if (o == null || getClass() != o.getClass()) return false;
1450
1451 Light light = (Light) o;
1452
1453 if (color != light.color) return false;
1454 if (onMs != light.onMs) return false;
1455 return offMs == light.offMs;
1456
1457 }
1458
1459 @Override
1460 public int hashCode() {
1461 int result = color;
1462 result = 31 * result + onMs;
1463 result = 31 * result + offMs;
1464 return result;
1465 }
1466
1467 @Override
1468 public String toString() {
1469 return "Light{" +
1470 "color=" + color +
1471 ", onMs=" + onMs +
1472 ", offMs=" + offMs +
1473 '}';
1474 }
1475 }
Chris Wren333a61c2014-05-28 16:40:57 -04001476}