blob: de9312041c41fea3029477553d0c8e04d8b7d279 [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;
Chris Wren333a61c2014-05-28 16:40:57 -040037import android.content.pm.PackageManager.NameNotFoundException;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060038import android.content.pm.PackageManagerInternal;
Chris Wren333a61c2014-05-28 16:40:57 -040039import android.content.res.Resources;
40import android.graphics.Bitmap;
Dan Sandlerd63f9322015-05-06 15:18:49 -040041import android.graphics.drawable.Icon;
John Spurlockbfa5dc42014-07-28 23:30:45 -040042import android.media.AudioAttributes;
Julia Reynolds0c299d42016-11-15 14:37:04 -050043import android.media.AudioSystem;
Chris Wren9eb5e102017-01-26 13:15:06 -050044import android.metrics.LogMaker;
Julia Reynolds0c299d42016-11-15 14:37:04 -050045import android.net.Uri;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060046import android.os.Binder;
Julia Reynolds0c299d42016-11-15 14:37:04 -050047import android.os.Build;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040048import android.os.Bundle;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060049import android.os.IBinder;
Chris Wrenda4bd202014-09-04 15:53:52 -040050import android.os.UserHandle;
Julia Reynolds0c299d42016-11-15 14:37:04 -050051import android.provider.Settings;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040052import android.service.notification.Adjustment;
Julia Reynolds5d25ee72015-11-20 15:38:20 -050053import android.service.notification.NotificationListenerService;
Julia Reynoldsc9842c12017-02-07 12:46:41 -050054import android.service.notification.NotificationRecordProto;
Julia Reynolds503ed942017-10-04 16:04:56 -040055import android.service.notification.NotificationStats;
Julia Reynolds22f02b32016-12-01 15:05:13 -050056import android.service.notification.SnoozeCriterion;
Chris Wren333a61c2014-05-28 16:40:57 -040057import android.service.notification.StatusBarNotification;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -050058import android.text.TextUtils;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040059import android.util.ArraySet;
Julia Reynoldsf0f629f2016-02-25 09:34:04 -050060import android.util.Log;
Julia Reynolds2a128742016-11-28 14:29:25 -050061import android.util.TimeUtils;
Julia Reynoldsc9842c12017-02-07 12:46:41 -050062import android.util.proto.ProtoOutputStream;
Dan Sandler0a2308e2017-05-30 19:50:42 -040063import android.widget.RemoteViews;
John Spurlockbfa5dc42014-07-28 23:30:45 -040064
Chris Wren1031c972014-07-23 13:11:45 +000065import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -050066import com.android.internal.logging.MetricsLogger;
67import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Chris Wren6650e572015-05-15 17:19:25 -040068import com.android.server.EventLogTags;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060069import com.android.server.LocalServices;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070070import com.android.server.uri.UriGrantsManagerInternal;
Chris Wren333a61c2014-05-28 16:40:57 -040071
72import java.io.PrintWriter;
73import java.lang.reflect.Array;
Julia Reynolds22f02b32016-12-01 15:05:13 -050074import java.util.ArrayList;
Chris Wren333a61c2014-05-28 16:40:57 -040075import java.util.Arrays;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040076import java.util.List;
John Spurlock312d1d02014-07-08 10:24:57 -040077import java.util.Objects;
Chris Wren333a61c2014-05-28 16:40:57 -040078
79/**
80 * Holds data about notifications that should not be shared with the
81 * {@link android.service.notification.NotificationListenerService}s.
82 *
83 * <p>These objects should not be mutated unless the code is synchronized
Julia Reynolds88860ce2017-06-01 16:55:49 -040084 * on {@link NotificationManagerService#mNotificationLock}, and any
Chris Wren333a61c2014-05-28 16:40:57 -040085 * modification should be followed by a sorting of that list.</p>
86 *
87 * <p>Is sortable by {@link NotificationComparator}.</p>
88 *
89 * {@hide}
90 */
91public final class NotificationRecord {
Julia Reynoldsf0f629f2016-02-25 09:34:04 -050092 static final String TAG = "NotificationRecord";
93 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Julia Reynoldsd6730072019-01-04 12:52:52 -050094 // the period after which a notification is updated where it can make sound
95 private static final int MAX_SOUND_DELAY_MS = 2000;
Chris Wren333a61c2014-05-28 16:40:57 -040096 final StatusBarNotification sbn;
Julia Reynolds218871e2018-06-13 10:45:21 -040097 IActivityManager mAm;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070098 UriGrantsManagerInternal mUgmInternal;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060099 final int mTargetSdkVersion;
Christoph Studer365e4c32014-09-18 20:35:36 +0200100 final int mOriginalFlags;
Chris Wrenbdf33762015-12-04 15:50:51 -0500101 private final Context mContext;
Christoph Studer365e4c32014-09-18 20:35:36 +0200102
Chris Wren333a61c2014-05-28 16:40:57 -0400103 NotificationUsageStats.SingleNotificationStats stats;
104 boolean isCanceled;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600105 IBinder permissionOwner;
Chris Wren333a61c2014-05-28 16:40:57 -0400106
107 // These members are used by NotificationSignalExtractors
108 // to communicate with the ranking module.
109 private float mContactAffinity;
110 private boolean mRecentlyIntrusive;
Julia Reynolds309d1c82017-05-03 16:00:20 -0400111 private long mLastIntrusive;
Chris Wren333a61c2014-05-28 16:40:57 -0400112
113 // is this notification currently being intercepted by Zen Mode?
114 private boolean mIntercept;
Chris Wren333a61c2014-05-28 16:40:57 -0400115
Beverly5a20a5e2018-03-06 15:02:44 -0500116 // is this notification hidden since the app pkg is suspended?
117 private boolean mHidden;
118
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200119 // The timestamp used for ranking.
120 private long mRankingTimeMs;
121
Chris Wren640e3872015-04-21 13:23:18 -0400122 // The first post time, stable across updates.
123 private long mCreationTimeMs;
124
Chris Wren6650e572015-05-15 17:19:25 -0400125 // The most recent visibility event.
126 private long mVisibleSinceMs;
127
128 // The most recent update time, or the creation time if no updates.
Julia Reynoldsd6730072019-01-04 12:52:52 -0500129 @VisibleForTesting
130 final long mUpdateTimeMs;
Chris Wren6650e572015-05-15 17:19:25 -0400131
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400132 // The most recent interruption time, or the creation time if no updates. Differs from the
133 // above value because updates are filtered based on whether they actually interrupted the
134 // user
135 private long mInterruptionTimeMs;
136
Gus Prevas7306b902018-12-11 10:57:06 -0500137 // The most recent time the notification made noise or buzzed the device, or -1 if it did not.
138 private long mLastAudiblyAlertedMs;
139
Chris Wrena3446562014-06-03 18:11:47 -0400140 // Is this record an update of an old record?
141 public boolean isUpdate;
Chris Wren54bbef42014-07-09 18:37:56 -0400142 private int mPackagePriority;
Chris Wrena3446562014-06-03 18:11:47 -0400143
Chris Wren1031c972014-07-23 13:11:45 +0000144 private int mAuthoritativeRank;
Christoph Studercd4adf82014-08-19 17:50:49 +0200145 private String mGlobalSortKey;
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400146 private int mPackageVisibility;
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400147 private int mSystemImportance = IMPORTANCE_UNSPECIFIED;
148 private int mAssistantImportance = IMPORTANCE_UNSPECIFIED;
Chris Wren47633422016-01-22 09:56:59 -0500149 private int mImportance = IMPORTANCE_UNSPECIFIED;
Brad Stenning9a8b2c82018-08-03 14:14:26 -0700150 // Field used in global sort key to bypass normal notifications
151 private int mCriticality = CriticalNotificationExtractor.NORMAL;
Will Brockman934b8e32019-03-08 11:14:45 -0500152 // A MetricsEvent.NotificationImportanceExplanation, tracking source of mImportance.
153 private int mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN;
154 // A MetricsEvent.NotificationImportanceExplanation for initial importance.
155 private int mInitialImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN;
Chris Wren1031c972014-07-23 13:11:45 +0000156
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500157 private int mSuppressedVisualEffects = 0;
Julia Reynoldsef37f282016-02-12 09:11:27 -0500158 private String mUserExplanation;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000159 private boolean mPreChannelsNotification = true;
Julia Reynolds0c299d42016-11-15 14:37:04 -0500160 private Uri mSound;
161 private long[] mVibration;
162 private AudioAttributes mAttributes;
Julia Reynolds924eed12017-01-19 09:52:07 -0500163 private NotificationChannel mChannel;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500164 private ArrayList<String> mPeopleOverride;
165 private ArrayList<SnoozeCriterion> mSnoozeCriteria;
Julia Reynolds924eed12017-01-19 09:52:07 -0500166 private boolean mShowBadge;
Julia Reynolds4509ce72019-01-31 13:12:43 -0500167 private boolean mAllowBubble;
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500168 private Light mLight;
Gustav Sennton1463d832018-11-06 16:12:48 +0000169 /**
170 * This list contains system generated smart actions from NAS, app-generated smart actions are
Gustav Sennton005d7a02019-01-04 13:41:32 +0000171 * stored in Notification.actions with isContextual() set to true.
Gustav Sennton1463d832018-11-06 16:12:48 +0000172 */
173 private ArrayList<Notification.Action> mSystemGeneratedSmartActions;
Tony Makc9acf672018-07-20 13:58:24 +0200174 private ArrayList<CharSequence> mSmartReplies;
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500175
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400176 private final List<Adjustment> mAdjustments;
Julia Reynolds503ed942017-10-04 16:04:56 -0400177 private final NotificationStats mStats;
178 private int mUserSentiment;
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500179 private boolean mIsInterruptive;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400180 private boolean mTextChanged;
181 private boolean mRecordedInterruption;
Kenny Guy23991102018-04-05 21:18:38 +0100182 private int mNumberOfSmartRepliesAdded;
Gustav Senntond25a64d2018-12-07 10:58:39 +0000183 private int mNumberOfSmartActionsAdded;
184 private boolean mSuggestionsGeneratedByAssistant;
Milo Sredkov13d88112019-02-01 12:23:24 +0000185 private boolean mEditChoicesBeforeSending;
Kenny Guy23991102018-04-05 21:18:38 +0100186 private boolean mHasSeenSmartReplies;
Rohan Shah590e1b22018-04-10 23:48:47 -0400187 /**
188 * Whether this notification (and its channels) should be considered user locked. Used in
189 * conjunction with user sentiment calculation.
190 */
191 private boolean mIsAppImportanceLocked;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600192 private ArraySet<Uri> mGrantableUris;
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400193
Julia Reynolds924eed12017-01-19 09:52:07 -0500194 public NotificationRecord(Context context, StatusBarNotification sbn,
Rohan Shah590e1b22018-04-10 23:48:47 -0400195 NotificationChannel channel) {
Chris Wren333a61c2014-05-28 16:40:57 -0400196 this.sbn = sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600197 mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class)
198 .getPackageTargetSdkVersion(sbn.getPackageName());
Julia Reynolds218871e2018-06-13 10:45:21 -0400199 mAm = ActivityManager.getService();
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700200 mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
Christoph Studer365e4c32014-09-18 20:35:36 +0200201 mOriginalFlags = sbn.getNotification().flags;
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200202 mRankingTimeMs = calculateRankingTimeMs(0L);
Chris Wren640e3872015-04-21 13:23:18 -0400203 mCreationTimeMs = sbn.getPostTime();
Chris Wren6650e572015-05-15 17:19:25 -0400204 mUpdateTimeMs = mCreationTimeMs;
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400205 mInterruptionTimeMs = mCreationTimeMs;
Chris Wrenbdf33762015-12-04 15:50:51 -0500206 mContext = context;
Chris Wrencdee8cd2016-01-25 17:10:30 -0500207 stats = new NotificationUsageStats.SingleNotificationStats();
Julia Reynolds924eed12017-01-19 09:52:07 -0500208 mChannel = channel;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000209 mPreChannelsNotification = isPreChannelsNotification();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500210 mSound = calculateSound();
211 mVibration = calculateVibration();
212 mAttributes = calculateAttributes();
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400213 mImportance = calculateInitialImportance();
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500214 mLight = calculateLights();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400215 mAdjustments = new ArrayList<>();
Julia Reynolds503ed942017-10-04 16:04:56 -0400216 mStats = new NotificationStats();
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500217 calculateUserSentiment();
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600218 calculateGrantableUris();
Chris Wrenbdf33762015-12-04 15:50:51 -0500219 }
220
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000221 private boolean isPreChannelsNotification() {
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600222 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) {
223 if (mTargetSdkVersion < Build.VERSION_CODES.O) {
224 return true;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000225 }
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000226 }
227 return false;
228 }
229
Julia Reynolds0c299d42016-11-15 14:37:04 -0500230 private Uri calculateSound() {
Chris Wrenbdf33762015-12-04 15:50:51 -0500231 final Notification n = sbn.getNotification();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500232
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700233 // No notification sounds on tv
234 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
235 return null;
236 }
237
Julia Reynolds924eed12017-01-19 09:52:07 -0500238 Uri sound = mChannel.getSound();
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000239 if (mPreChannelsNotification && (getChannel().getUserLockedFields()
Julia Reynolds0c299d42016-11-15 14:37:04 -0500240 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
241
242 final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0;
243 if (useDefaultSound) {
244 sound = Settings.System.DEFAULT_NOTIFICATION_URI;
Julia Reynoldsb9e712e2017-04-17 10:31:03 -0400245 } else {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500246 sound = n.sound;
247 }
248 }
249 return sound;
250 }
251
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500252 private Light calculateLights() {
253 int defaultLightColor = mContext.getResources().getColor(
254 com.android.internal.R.color.config_defaultNotificationColor);
255 int defaultLightOn = mContext.getResources().getInteger(
256 com.android.internal.R.integer.config_defaultNotificationLedOn);
257 int defaultLightOff = mContext.getResources().getInteger(
258 com.android.internal.R.integer.config_defaultNotificationLedOff);
259
Julia Reynolds529e3322017-02-06 08:33:01 -0500260 int channelLightColor = getChannel().getLightColor() != 0 ? getChannel().getLightColor()
261 : defaultLightColor;
262 Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500263 defaultLightOn, defaultLightOff) : null;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000264 if (mPreChannelsNotification
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500265 && (getChannel().getUserLockedFields()
266 & NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
267 final Notification notification = sbn.getNotification();
268 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
269 light = new Light(notification.ledARGB, notification.ledOnMS,
270 notification.ledOffMS);
271 if ((notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
272 light = new Light(defaultLightColor, defaultLightOn,
273 defaultLightOff);
274 }
275 } else {
276 light = null;
277 }
278 }
279 return light;
280 }
281
Julia Reynolds0c299d42016-11-15 14:37:04 -0500282 private long[] calculateVibration() {
283 long[] vibration;
284 final long[] defaultVibration = NotificationManagerService.getLongArray(
285 mContext.getResources(),
286 com.android.internal.R.array.config_defaultNotificationVibePattern,
287 NotificationManagerService.VIBRATE_PATTERN_MAXLEN,
288 NotificationManagerService.DEFAULT_VIBRATE_PATTERN);
289 if (getChannel().shouldVibrate()) {
Julia Reynoldsf57de462016-11-23 11:31:46 -0500290 vibration = getChannel().getVibrationPattern() == null
291 ? defaultVibration : getChannel().getVibrationPattern();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500292 } else {
293 vibration = null;
294 }
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000295 if (mPreChannelsNotification
Julia Reynolds0c299d42016-11-15 14:37:04 -0500296 && (getChannel().getUserLockedFields()
297 & NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
298 final Notification notification = sbn.getNotification();
299 final boolean useDefaultVibrate =
300 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
301 if (useDefaultVibrate) {
302 vibration = defaultVibration;
303 } else {
304 vibration = notification.vibrate;
305 }
306 }
307 return vibration;
308 }
309
310 private AudioAttributes calculateAttributes() {
311 final Notification n = sbn.getNotification();
Julia Reynolds619a69f2017-01-27 15:11:38 -0500312 AudioAttributes attributes = getChannel().getAudioAttributes();
313 if (attributes == null) {
314 attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
315 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500316
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000317 if (mPreChannelsNotification
Julia Reynolds619a69f2017-01-27 15:11:38 -0500318 && (getChannel().getUserLockedFields()
319 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
320 if (n.audioAttributes != null) {
321 // prefer audio attributes to stream type
322 attributes = n.audioAttributes;
323 } else if (n.audioStreamType >= 0
324 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
325 // the stream type is valid, use it
326 attributes = new AudioAttributes.Builder()
327 .setInternalLegacyStreamType(n.audioStreamType)
328 .build();
329 } else if (n.audioStreamType != AudioSystem.STREAM_DEFAULT) {
330 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
331 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500332 }
333 return attributes;
334 }
335
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400336 private int calculateInitialImportance() {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500337 final Notification n = sbn.getNotification();
Will Brockman934b8e32019-03-08 11:14:45 -0500338 int importance = getChannel().getImportance(); // Post-channels notifications use this
339 mInitialImportanceExplanationCode = getChannel().hasUserSetImportance()
340 ? MetricsEvent.IMPORTANCE_EXPLANATION_USER
341 : MetricsEvent.IMPORTANCE_EXPLANATION_APP;
Chris Wrenbdf33762015-12-04 15:50:51 -0500342
Will Brockman934b8e32019-03-08 11:14:45 -0500343 // Migrate notification priority flag to a priority value.
Chris Wrenbdf33762015-12-04 15:50:51 -0500344 if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) {
345 n.priority = Notification.PRIORITY_MAX;
346 }
347
Will Brockman934b8e32019-03-08 11:14:45 -0500348 // Convert priority value to an importance value, used only for pre-channels notifications.
349 int requestedImportance = IMPORTANCE_DEFAULT;
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500350 n.priority = NotificationManagerService.clamp(n.priority, Notification.PRIORITY_MIN,
351 Notification.PRIORITY_MAX);
Chris Wrenbdf33762015-12-04 15:50:51 -0500352 switch (n.priority) {
353 case Notification.PRIORITY_MIN:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500354 requestedImportance = IMPORTANCE_MIN;
Julia Reynoldsf0f629f2016-02-25 09:34:04 -0500355 break;
Chris Wrenbdf33762015-12-04 15:50:51 -0500356 case Notification.PRIORITY_LOW:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500357 requestedImportance = IMPORTANCE_LOW;
Chris Wrenbdf33762015-12-04 15:50:51 -0500358 break;
359 case Notification.PRIORITY_DEFAULT:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500360 requestedImportance = IMPORTANCE_DEFAULT;
Chris Wrenbdf33762015-12-04 15:50:51 -0500361 break;
362 case Notification.PRIORITY_HIGH:
Chris Wrenbdf33762015-12-04 15:50:51 -0500363 case Notification.PRIORITY_MAX:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500364 requestedImportance = IMPORTANCE_HIGH;
Chris Wrenbdf33762015-12-04 15:50:51 -0500365 break;
366 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500367 stats.requestedImportance = requestedImportance;
368 stats.isNoisy = mSound != null || mVibration != null;
Chris Wrenbdf33762015-12-04 15:50:51 -0500369
Will Brockman934b8e32019-03-08 11:14:45 -0500370 // For pre-channels notifications, apply system overrides and then use requestedImportance
371 // as importance.
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000372 if (mPreChannelsNotification
Julia Reynoldsa917a112017-03-21 11:09:14 -0400373 && (importance == IMPORTANCE_UNSPECIFIED
Will Brockman934b8e32019-03-08 11:14:45 -0500374 || (!getChannel().hasUserSetImportance()))) {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500375 if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) {
376 requestedImportance = IMPORTANCE_LOW;
Julia Reynolds83fa1072016-02-17 09:10:19 -0500377 }
Julia Reynolds83fa1072016-02-17 09:10:19 -0500378
Julia Reynolds0c299d42016-11-15 14:37:04 -0500379 if (stats.isNoisy) {
380 if (requestedImportance < IMPORTANCE_DEFAULT) {
381 requestedImportance = IMPORTANCE_DEFAULT;
382 }
383 }
384
385 if (n.fullScreenIntent != null) {
386 requestedImportance = IMPORTANCE_HIGH;
387 }
388 importance = requestedImportance;
Will Brockman934b8e32019-03-08 11:14:45 -0500389 mInitialImportanceExplanationCode =
390 MetricsEvent.IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS;
Chris Wrenbdf33762015-12-04 15:50:51 -0500391 }
392
Chris Wrencdee8cd2016-01-25 17:10:30 -0500393 stats.naturalImportance = importance;
Chris Wrenbdf33762015-12-04 15:50:51 -0500394 return importance;
Chris Wren333a61c2014-05-28 16:40:57 -0400395 }
396
397 // copy any notes that the ranking system may have made before the update
398 public void copyRankingInformation(NotificationRecord previous) {
399 mContactAffinity = previous.mContactAffinity;
400 mRecentlyIntrusive = previous.mRecentlyIntrusive;
Chris Wren54bbef42014-07-09 18:37:56 -0400401 mPackagePriority = previous.mPackagePriority;
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400402 mPackageVisibility = previous.mPackageVisibility;
Chris Wren333a61c2014-05-28 16:40:57 -0400403 mIntercept = previous.mIntercept;
Beverly5a20a5e2018-03-06 15:02:44 -0500404 mHidden = previous.mHidden;
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200405 mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
Chris Wren640e3872015-04-21 13:23:18 -0400406 mCreationTimeMs = previous.mCreationTimeMs;
Chris Wren6650e572015-05-15 17:19:25 -0400407 mVisibleSinceMs = previous.mVisibleSinceMs;
Selim Cinek5b03ce92016-05-18 15:16:58 -0700408 if (previous.sbn.getOverrideGroupKey() != null && !sbn.isAppGroup()) {
Chris Wren8a1638f2016-05-02 16:19:14 -0400409 sbn.setOverrideGroupKey(previous.sbn.getOverrideGroupKey());
410 }
Chris Wren1f602dc2016-04-11 10:33:46 -0400411 // Don't copy importance information or mGlobalSortKey, recompute them.
Chris Wren333a61c2014-05-28 16:40:57 -0400412 }
413
414 public Notification getNotification() { return sbn.getNotification(); }
415 public int getFlags() { return sbn.getNotification().flags; }
Chris Wrenda4bd202014-09-04 15:53:52 -0400416 public UserHandle getUser() { return sbn.getUser(); }
Chris Wren333a61c2014-05-28 16:40:57 -0400417 public String getKey() { return sbn.getKey(); }
Chris Wrenda4bd202014-09-04 15:53:52 -0400418 /** @deprecated Use {@link #getUser()} instead. */
419 public int getUserId() { return sbn.getUserId(); }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600420 public int getUid() { return sbn.getUid(); }
Chris Wren333a61c2014-05-28 16:40:57 -0400421
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800422 void dump(ProtoOutputStream proto, long fieldId, boolean redact, int state) {
423 final long token = proto.start(fieldId);
424
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500425 proto.write(NotificationRecordProto.KEY, sbn.getKey());
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800426 proto.write(NotificationRecordProto.STATE, state);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500427 if (getChannel() != null) {
428 proto.write(NotificationRecordProto.CHANNEL_ID, getChannel().getId());
429 }
430 proto.write(NotificationRecordProto.CAN_SHOW_LIGHT, getLight() != null);
431 proto.write(NotificationRecordProto.CAN_VIBRATE, getVibration() != null);
432 proto.write(NotificationRecordProto.FLAGS, sbn.getNotification().flags);
433 proto.write(NotificationRecordProto.GROUP_KEY, getGroupKey());
434 proto.write(NotificationRecordProto.IMPORTANCE, getImportance());
435 if (getSound() != null) {
436 proto.write(NotificationRecordProto.SOUND, getSound().toString());
437 }
438 if (getAudioAttributes() != null) {
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800439 getAudioAttributes().writeToProto(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500440 }
Julia Reynolds98460762019-03-18 13:13:55 -0400441 proto.write(NotificationRecordProto.PACKAGE, sbn.getPackageName());
442 proto.write(NotificationRecordProto.DELEGATE_PACKAGE, sbn.getOpPkg());
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800443
444 proto.end(token);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500445 }
446
Dan Sandler0a2308e2017-05-30 19:50:42 -0400447 String formatRemoteViews(RemoteViews rv) {
448 if (rv == null) return "null";
449 return String.format("%s/0x%08x (%d bytes): %s",
450 rv.getPackage(), rv.getLayoutId(), rv.estimateMemoryUsage(), rv.toString());
451 }
452
Dan Sandlera1770312015-07-10 13:59:29 -0400453 void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
Chris Wren333a61c2014-05-28 16:40:57 -0400454 final Notification notification = sbn.getNotification();
Dan Sandlerd63f9322015-05-06 15:18:49 -0400455 final Icon icon = notification.getSmallIcon();
456 String iconStr = String.valueOf(icon);
457 if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
458 iconStr += " / " + idDebugString(baseContext, icon.getResPackage(), icon.getResId());
459 }
Chris Wren333a61c2014-05-28 16:40:57 -0400460 pw.println(prefix + this);
Dan Sandler0a2308e2017-05-30 19:50:42 -0400461 prefix = prefix + " ";
Julia Reynoldsa917a112017-03-21 11:09:14 -0400462 pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
Julia Reynolds98460762019-03-18 13:13:55 -0400463 pw.println(prefix + "opPkg=" + sbn.getOpPkg());
Julia Reynoldsa917a112017-03-21 11:09:14 -0400464 pw.println(prefix + "icon=" + iconStr);
Julia Reynolds4db59552017-06-30 13:34:01 -0400465 pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400466 pw.println(prefix + "pri=" + notification.priority);
467 pw.println(prefix + "key=" + sbn.getKey());
Julia Reynolds503ed942017-10-04 16:04:56 -0400468 pw.println(prefix + "seen=" + mStats.hasSeen());
Julia Reynoldsa917a112017-03-21 11:09:14 -0400469 pw.println(prefix + "groupKey=" + getGroupKey());
470 pw.println(prefix + "fullscreenIntent=" + notification.fullScreenIntent);
471 pw.println(prefix + "contentIntent=" + notification.contentIntent);
472 pw.println(prefix + "deleteIntent=" + notification.deleteIntent);
Aaron Heuckrothb4d6aa72018-07-02 14:58:33 -0400473 pw.println(prefix + "number=" + notification.number);
474 pw.println(prefix + "groupAlertBehavior=" + notification.getGroupAlertBehavior());
Dan Sandler0b4ceb32017-03-29 14:13:55 -0400475
476 pw.print(prefix + "tickerText=");
477 if (!TextUtils.isEmpty(notification.tickerText)) {
478 final String ticker = notification.tickerText.toString();
479 if (redact) {
480 // if the string is long enough, we allow ourselves a few bytes for debugging
481 pw.print(ticker.length() > 16 ? ticker.substring(0,8) : "");
482 pw.println("...");
483 } else {
484 pw.println(ticker);
485 }
486 } else {
487 pw.println("null");
488 }
Dan Sandler0a2308e2017-05-30 19:50:42 -0400489 pw.println(prefix + "contentView=" + formatRemoteViews(notification.contentView));
490 pw.println(prefix + "bigContentView=" + formatRemoteViews(notification.bigContentView));
491 pw.println(prefix + "headsUpContentView="
492 + formatRemoteViews(notification.headsUpContentView));
493 pw.print(prefix + String.format("color=0x%08x", notification.color));
Julia Reynoldsbad42972017-04-25 13:52:49 -0400494 pw.println(prefix + "timeout="
495 + TimeUtils.formatForLogging(notification.getTimeoutAfter()));
Chris Wren333a61c2014-05-28 16:40:57 -0400496 if (notification.actions != null && notification.actions.length > 0) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400497 pw.println(prefix + "actions={");
Chris Wren333a61c2014-05-28 16:40:57 -0400498 final int N = notification.actions.length;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500499 for (int i = 0; i < N; i++) {
Chris Wren333a61c2014-05-28 16:40:57 -0400500 final Notification.Action action = notification.actions[i];
Chris Wren1ac52a92016-02-24 14:54:52 -0500501 if (action != null) {
502 pw.println(String.format("%s [%d] \"%s\" -> %s",
503 prefix,
504 i,
505 action.title,
506 action.actionIntent == null ? "null" : action.actionIntent.toString()
507 ));
508 }
Chris Wren333a61c2014-05-28 16:40:57 -0400509 }
510 pw.println(prefix + " }");
511 }
512 if (notification.extras != null && notification.extras.size() > 0) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400513 pw.println(prefix + "extras={");
Chris Wren333a61c2014-05-28 16:40:57 -0400514 for (String key : notification.extras.keySet()) {
515 pw.print(prefix + " " + key + "=");
516 Object val = notification.extras.get(key);
517 if (val == null) {
518 pw.println("null");
519 } else {
520 pw.print(val.getClass().getSimpleName());
Dan Sandlera1770312015-07-10 13:59:29 -0400521 if (redact && (val instanceof CharSequence || val instanceof String)) {
Chris Wren333a61c2014-05-28 16:40:57 -0400522 // redact contents from bugreports
523 } else if (val instanceof Bitmap) {
524 pw.print(String.format(" (%dx%d)",
525 ((Bitmap) val).getWidth(),
526 ((Bitmap) val).getHeight()));
527 } else if (val.getClass().isArray()) {
528 final int N = Array.getLength(val);
Dan Sandlera1770312015-07-10 13:59:29 -0400529 pw.print(" (" + N + ")");
530 if (!redact) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500531 for (int j = 0; j < N; j++) {
Dan Sandlera1770312015-07-10 13:59:29 -0400532 pw.println();
533 pw.print(String.format("%s [%d] %s",
534 prefix, j, String.valueOf(Array.get(val, j))));
535 }
536 }
Chris Wren333a61c2014-05-28 16:40:57 -0400537 } else {
538 pw.print(" (" + String.valueOf(val) + ")");
539 }
540 pw.println();
541 }
542 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400543 pw.println(prefix + "}");
Chris Wren333a61c2014-05-28 16:40:57 -0400544 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400545 pw.println(prefix + "stats=" + stats.toString());
546 pw.println(prefix + "mContactAffinity=" + mContactAffinity);
547 pw.println(prefix + "mRecentlyIntrusive=" + mRecentlyIntrusive);
548 pw.println(prefix + "mPackagePriority=" + mPackagePriority);
549 pw.println(prefix + "mPackageVisibility=" + mPackageVisibility);
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400550 pw.println(prefix + "mSystemImportance="
551 + NotificationListenerService.Ranking.importanceToString(mSystemImportance));
552 pw.println(prefix + "mAsstImportance="
553 + NotificationListenerService.Ranking.importanceToString(mAssistantImportance));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400554 pw.println(prefix + "mImportance="
Chris Wrenbdf33762015-12-04 15:50:51 -0500555 + NotificationListenerService.Ranking.importanceToString(mImportance));
Will Brockman934b8e32019-03-08 11:14:45 -0500556 pw.println(prefix + "mImportanceExplanation=" + getImportanceExplanation());
Rohan Shah590e1b22018-04-10 23:48:47 -0400557 pw.println(prefix + "mIsAppImportanceLocked=" + mIsAppImportanceLocked);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400558 pw.println(prefix + "mIntercept=" + mIntercept);
Beverly5a20a5e2018-03-06 15:02:44 -0500559 pw.println(prefix + "mHidden==" + mHidden);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400560 pw.println(prefix + "mGlobalSortKey=" + mGlobalSortKey);
561 pw.println(prefix + "mRankingTimeMs=" + mRankingTimeMs);
562 pw.println(prefix + "mCreationTimeMs=" + mCreationTimeMs);
563 pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
564 pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400565 pw.println(prefix + "mInterruptionTimeMs=" + mInterruptionTimeMs);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400566 pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000567 if (mPreChannelsNotification) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400568 pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500569 notification.defaults, notification.flags));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400570 pw.println(prefix + "n.sound=" + notification.sound);
571 pw.println(prefix + "n.audioStreamType=" + notification.audioStreamType);
572 pw.println(prefix + "n.audioAttributes=" + notification.audioAttributes);
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500573 pw.println(prefix + String.format(" led=0x%08x onMs=%d offMs=%d",
574 notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400575 pw.println(prefix + "vibrate=" + Arrays.toString(notification.vibrate));
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500576 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400577 pw.println(prefix + "mSound= " + mSound);
578 pw.println(prefix + "mVibration= " + mVibration);
579 pw.println(prefix + "mAttributes= " + mAttributes);
580 pw.println(prefix + "mLight= " + mLight);
581 pw.println(prefix + "mShowBadge=" + mShowBadge);
Julia Reynolds4db59552017-06-30 13:34:01 -0400582 pw.println(prefix + "mColorized=" + notification.isColorized());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500583 pw.println(prefix + "mIsInterruptive=" + mIsInterruptive);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400584 pw.println(prefix + "effectiveNotificationChannel=" + getChannel());
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500585 if (getPeopleOverride() != null) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400586 pw.println(prefix + "overridePeople= " + TextUtils.join(",", getPeopleOverride()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500587 }
588 if (getSnoozeCriteria() != null) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400589 pw.println(prefix + "snoozeCriteria=" + TextUtils.join(",", getSnoozeCriteria()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500590 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400591 pw.println(prefix + "mAdjustments=" + mAdjustments);
Chris Wren333a61c2014-05-28 16:40:57 -0400592 }
593
594
595 static String idDebugString(Context baseContext, String packageName, int id) {
596 Context c;
597
598 if (packageName != null) {
599 try {
600 c = baseContext.createPackageContext(packageName, 0);
601 } catch (NameNotFoundException e) {
602 c = baseContext;
603 }
604 } else {
605 c = baseContext;
606 }
607
608 Resources r = c.getResources();
609 try {
610 return r.getResourceName(id);
611 } catch (Resources.NotFoundException e) {
612 return "<name unknown>";
613 }
614 }
615
616 @Override
617 public final String toString() {
618 return String.format(
Julia Reynolds85769912016-10-25 09:08:57 -0400619 "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s importance=%d key=%s" +
Rohan Shah590e1b22018-04-10 23:48:47 -0400620 "appImportanceLocked=%s: %s)",
Chris Wren333a61c2014-05-28 16:40:57 -0400621 System.identityHashCode(this),
622 this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(),
Julia Reynolds4db59552017-06-30 13:34:01 -0400623 this.sbn.getTag(), this.mImportance, this.sbn.getKey(),
Rohan Shah590e1b22018-04-10 23:48:47 -0400624 mIsAppImportanceLocked, this.sbn.getNotification());
Chris Wren333a61c2014-05-28 16:40:57 -0400625 }
626
Julia Reynolds27c0a962018-12-10 12:37:28 -0500627 public boolean hasAdjustment(String key) {
628 synchronized (mAdjustments) {
629 for (Adjustment adjustment : mAdjustments) {
630 if (adjustment.getSignals().containsKey(key)) {
631 return true;
632 }
633 }
634 }
635 return false;
636 }
637
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400638 public void addAdjustment(Adjustment adjustment) {
639 synchronized (mAdjustments) {
640 mAdjustments.add(adjustment);
641 }
642 }
643
644 public void applyAdjustments() {
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400645 long now = System.currentTimeMillis();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400646 synchronized (mAdjustments) {
647 for (Adjustment adjustment: mAdjustments) {
648 Bundle signals = adjustment.getSignals();
649 if (signals.containsKey(Adjustment.KEY_PEOPLE)) {
650 final ArrayList<String> people =
651 adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
652 setPeopleOverride(people);
653 }
654 if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) {
655 final ArrayList<SnoozeCriterion> snoozeCriterionList =
656 adjustment.getSignals().getParcelableArrayList(
657 Adjustment.KEY_SNOOZE_CRITERIA);
658 setSnoozeCriteria(snoozeCriterionList);
659 }
660 if (signals.containsKey(Adjustment.KEY_GROUP_KEY)) {
661 final String groupOverrideKey =
662 adjustment.getSignals().getString(Adjustment.KEY_GROUP_KEY);
663 setOverrideGroupKey(groupOverrideKey);
664 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400665 if (signals.containsKey(Adjustment.KEY_USER_SENTIMENT)) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500666 // Only allow user sentiment update from assistant if user hasn't already
667 // expressed a preference for this channel
Rohan Shah590e1b22018-04-10 23:48:47 -0400668 if (!mIsAppImportanceLocked
669 && (getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500670 setUserSentiment(adjustment.getSignals().getInt(
671 Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEUTRAL));
672 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400673 }
Tony Maka4716992019-01-24 15:41:59 +0000674 if (signals.containsKey(Adjustment.KEY_CONTEXTUAL_ACTIONS)) {
Gustav Sennton1463d832018-11-06 16:12:48 +0000675 setSystemGeneratedSmartActions(
Tony Maka4716992019-01-24 15:41:59 +0000676 signals.getParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS));
Tony Mak628cb932018-06-19 18:30:41 +0100677 }
Tony Maka4716992019-01-24 15:41:59 +0000678 if (signals.containsKey(Adjustment.KEY_TEXT_REPLIES)) {
679 setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_TEXT_REPLIES));
Tony Makc9acf672018-07-20 13:58:24 +0200680 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400681 if (signals.containsKey(Adjustment.KEY_IMPORTANCE)) {
682 int importance = signals.getInt(Adjustment.KEY_IMPORTANCE);
683 importance = Math.max(IMPORTANCE_UNSPECIFIED, importance);
684 importance = Math.min(IMPORTANCE_HIGH, importance);
685 setAssistantImportance(importance);
686 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400687 }
Will Brockmanb020b5e2019-01-25 10:37:30 -0500688 // We have now gotten all the information out of the adjustments and can forget them.
689 mAdjustments.clear();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400690 }
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
786 && !getChannel().isImportanceLockedByOEM()) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400787 mImportance = mAssistantImportance;
Will Brockman934b8e32019-03-08 11:14:45 -0500788 mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_ASST;
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400789 }
790 if (mSystemImportance != IMPORTANCE_UNSPECIFIED) {
791 mImportance = mSystemImportance;
Will Brockman934b8e32019-03-08 11:14:45 -0500792 mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM;
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400793 }
Chris Wrenbdf33762015-12-04 15:50:51 -0500794 }
795
796 public int getImportance() {
797 return mImportance;
798 }
799
800 public CharSequence getImportanceExplanation() {
Will Brockman934b8e32019-03-08 11:14:45 -0500801 switch (mImportanceExplanationCode) {
802 case MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN:
803 return null;
804 case MetricsEvent.IMPORTANCE_EXPLANATION_APP:
805 case MetricsEvent.IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS:
806 return "app";
807 case MetricsEvent.IMPORTANCE_EXPLANATION_USER:
808 return "user";
809 case MetricsEvent.IMPORTANCE_EXPLANATION_ASST:
810 return "asst";
811 case MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM:
812 return "system";
813 }
814 return null;
Chris Wrenbdf33762015-12-04 15:50:51 -0500815 }
816
Chris Wren333a61c2014-05-28 16:40:57 -0400817 public boolean setIntercepted(boolean intercept) {
818 mIntercept = intercept;
819 return mIntercept;
820 }
821
Brad Stenning9a8b2c82018-08-03 14:14:26 -0700822 /**
823 * Set to affect global sort key.
824 *
825 * @param criticality used in a string based sort thus 0 is the most critical
826 */
827 public void setCriticality(int criticality) {
828 mCriticality = criticality;
829 }
830
831 public int getCriticality() {
832 return mCriticality;
833 }
834
Chris Wren333a61c2014-05-28 16:40:57 -0400835 public boolean isIntercepted() {
836 return mIntercept;
837 }
838
Julia Reynoldsd6730072019-01-04 12:52:52 -0500839 public boolean isNewEnoughForAlerting(long now) {
840 return getFreshnessMs(now) <= MAX_SOUND_DELAY_MS;
841 }
842
Beverly5a20a5e2018-03-06 15:02:44 -0500843 public void setHidden(boolean hidden) {
844 mHidden = hidden;
845 }
846
847 public boolean isHidden() {
848 return mHidden;
849 }
850
851
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500852 public void setSuppressedVisualEffects(int effects) {
853 mSuppressedVisualEffects = effects;
854 }
855
856 public int getSuppressedVisualEffects() {
857 return mSuppressedVisualEffects;
858 }
859
John Spurlock312d1d02014-07-08 10:24:57 -0400860 public boolean isCategory(String category) {
John Spurlockbfa5dc42014-07-28 23:30:45 -0400861 return Objects.equals(getNotification().category, category);
862 }
863
John Spurlockbfa5dc42014-07-28 23:30:45 -0400864 public boolean isAudioAttributesUsage(int usage) {
Julia Reynolds51eb78f82018-03-07 07:35:21 -0500865 return mAttributes != null && mAttributes.getUsage() == usage;
John Spurlock312d1d02014-07-08 10:24:57 -0400866 }
867
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200868 /**
869 * Returns the timestamp to use for time-based sorting in the ranker.
870 */
871 public long getRankingTimeMs() {
872 return mRankingTimeMs;
873 }
874
875 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400876 * @param now this current time in milliseconds.
877 * @returns the number of milliseconds since the most recent update, or the post time if none.
Chris Wren6650e572015-05-15 17:19:25 -0400878 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400879 public int getFreshnessMs(long now) {
880 return (int) (now - mUpdateTimeMs);
Chris Wren6650e572015-05-15 17:19:25 -0400881 }
882
883 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400884 * @param now this current time in milliseconds.
885 * @returns the number of milliseconds since the the first post, ignoring updates.
Chris Wren640e3872015-04-21 13:23:18 -0400886 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400887 public int getLifespanMs(long now) {
888 return (int) (now - mCreationTimeMs);
Chris Wren640e3872015-04-21 13:23:18 -0400889 }
890
891 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400892 * @param now this current time in milliseconds.
893 * @returns the number of milliseconds since the most recent visibility event, or 0 if never.
Chris Wren6650e572015-05-15 17:19:25 -0400894 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400895 public int getExposureMs(long now) {
896 return mVisibleSinceMs == 0 ? 0 : (int) (now - mVisibleSinceMs);
Chris Wren6650e572015-05-15 17:19:25 -0400897 }
898
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400899 public int getInterruptionMs(long now) {
900 return (int) (now - mInterruptionTimeMs);
901 }
902
Chris Wren6650e572015-05-15 17:19:25 -0400903 /**
904 * Set the visibility of the notification.
905 */
Dieter Hsud39f0d52018-04-14 02:08:30 +0800906 public void setVisibility(boolean visible, int rank, int count) {
Chris Wren6650e572015-05-15 17:19:25 -0400907 final long now = System.currentTimeMillis();
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400908 mVisibleSinceMs = visible ? now : mVisibleSinceMs;
Chris Wren6650e572015-05-15 17:19:25 -0400909 stats.onVisibilityChanged(visible);
Chris Wren9eb5e102017-01-26 13:15:06 -0500910 MetricsLogger.action(getLogMaker(now)
911 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
912 .setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800913 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
914 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count));
Chris Wren9eb5e102017-01-26 13:15:06 -0500915 if (visible) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400916 setSeen();
Chris Wren9eb5e102017-01-26 13:15:06 -0500917 MetricsLogger.histogram(mContext, "note_freshness", getFreshnessMs(now));
918 }
Chris Wren6650e572015-05-15 17:19:25 -0400919 EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0,
Chris Wren9eb5e102017-01-26 13:15:06 -0500920 getLifespanMs(now),
921 getFreshnessMs(now),
Chris Wrend1dbc922015-06-19 17:51:16 -0400922 0, // exposure time
923 rank);
Chris Wren6650e572015-05-15 17:19:25 -0400924 }
925
926 /**
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200927 * @param previousRankingTimeMs for updated notifications, {@link #getRankingTimeMs()}
928 * of the previous notification record, 0 otherwise
929 */
930 private long calculateRankingTimeMs(long previousRankingTimeMs) {
931 Notification n = getNotification();
932 // Take developer provided 'when', unless it's in the future.
933 if (n.when != 0 && n.when <= sbn.getPostTime()) {
934 return n.when;
935 }
936 // If we've ranked a previous instance with a timestamp, inherit it. This case is
937 // important in order to have ranking stability for updating notifications.
938 if (previousRankingTimeMs > 0) {
939 return previousRankingTimeMs;
940 }
941 return sbn.getPostTime();
942 }
Chris Wren1031c972014-07-23 13:11:45 +0000943
Christoph Studercd4adf82014-08-19 17:50:49 +0200944 public void setGlobalSortKey(String globalSortKey) {
945 mGlobalSortKey = globalSortKey;
Chris Wren1031c972014-07-23 13:11:45 +0000946 }
947
Christoph Studercd4adf82014-08-19 17:50:49 +0200948 public String getGlobalSortKey() {
949 return mGlobalSortKey;
Chris Wren1031c972014-07-23 13:11:45 +0000950 }
951
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700952 /** Check if any of the listeners have marked this notification as seen by the user. */
953 public boolean isSeen() {
Julia Reynolds503ed942017-10-04 16:04:56 -0400954 return mStats.hasSeen();
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700955 }
956
957 /** Mark the notification as seen by the user. */
958 public void setSeen() {
Julia Reynolds503ed942017-10-04 16:04:56 -0400959 mStats.setSeen();
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400960 if (mTextChanged) {
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400961 setInterruptive(true);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400962 }
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700963 }
964
Chris Wren1031c972014-07-23 13:11:45 +0000965 public void setAuthoritativeRank(int authoritativeRank) {
966 mAuthoritativeRank = authoritativeRank;
967 }
968
969 public int getAuthoritativeRank() {
970 return mAuthoritativeRank;
971 }
972
973 public String getGroupKey() {
974 return sbn.getGroupKey();
975 }
Chris Wren47633422016-01-22 09:56:59 -0500976
Chris Wrenb3921792017-06-01 13:34:46 -0400977 public void setOverrideGroupKey(String overrideGroupKey) {
978 sbn.setOverrideGroupKey(overrideGroupKey);
Chris Wrenb3921792017-06-01 13:34:46 -0400979 }
980
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400981 public NotificationChannel getChannel() {
Julia Reynolds924eed12017-01-19 09:52:07 -0500982 return mChannel;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500983 }
984
Rohan Shah590e1b22018-04-10 23:48:47 -0400985 /**
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400986 * @see PreferencesHelper#getIsAppImportanceLocked(String, int)
Rohan Shah590e1b22018-04-10 23:48:47 -0400987 */
988 public boolean getIsAppImportanceLocked() {
989 return mIsAppImportanceLocked;
990 }
991
Julia Reynolds924eed12017-01-19 09:52:07 -0500992 protected void updateNotificationChannel(NotificationChannel channel) {
993 if (channel != null) {
994 mChannel = channel;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500995 calculateImportance();
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500996 calculateUserSentiment();
Julia Reynolds22f02b32016-12-01 15:05:13 -0500997 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400998 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500999
Julia Reynolds924eed12017-01-19 09:52:07 -05001000 public void setShowBadge(boolean showBadge) {
1001 mShowBadge = showBadge;
1002 }
1003
Julia Reynolds4509ce72019-01-31 13:12:43 -05001004 public boolean canBubble() {
1005 return mAllowBubble;
1006 }
1007
1008 public void setAllowBubble(boolean allow) {
1009 mAllowBubble = allow;
1010 }
1011
Julia Reynolds924eed12017-01-19 09:52:07 -05001012 public boolean canShowBadge() {
1013 return mShowBadge;
1014 }
1015
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05001016 public Light getLight() {
1017 return mLight;
1018 }
1019
Julia Reynolds0c299d42016-11-15 14:37:04 -05001020 public Uri getSound() {
1021 return mSound;
1022 }
1023
1024 public long[] getVibration() {
1025 return mVibration;
1026 }
1027
1028 public AudioAttributes getAudioAttributes() {
1029 return mAttributes;
1030 }
Julia Reynolds22f02b32016-12-01 15:05:13 -05001031
1032 public ArrayList<String> getPeopleOverride() {
1033 return mPeopleOverride;
1034 }
1035
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001036 public void setInterruptive(boolean interruptive) {
1037 mIsInterruptive = interruptive;
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -04001038 final long now = System.currentTimeMillis();
1039 mInterruptionTimeMs = interruptive ? now : mInterruptionTimeMs;
1040
1041 if (interruptive) {
1042 MetricsLogger.action(getLogMaker()
1043 .setCategory(MetricsEvent.NOTIFICATION_INTERRUPTION)
1044 .setType(MetricsEvent.TYPE_OPEN)
1045 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS,
1046 getInterruptionMs(now)));
1047 MetricsLogger.histogram(mContext, "note_interruptive", getInterruptionMs(now));
1048 }
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001049 }
1050
Gus Prevasa3226492018-10-23 11:10:09 -04001051 public void setAudiblyAlerted(boolean audiblyAlerted) {
Gus Prevas7306b902018-12-11 10:57:06 -05001052 mLastAudiblyAlertedMs = audiblyAlerted ? System.currentTimeMillis() : -1;
Gus Prevasa3226492018-10-23 11:10:09 -04001053 }
1054
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001055 public void setTextChanged(boolean textChanged) {
1056 mTextChanged = textChanged;
1057 }
1058
1059 public void setRecordedInterruption(boolean recorded) {
1060 mRecordedInterruption = recorded;
1061 }
1062
1063 public boolean hasRecordedInterruption() {
1064 return mRecordedInterruption;
1065 }
1066
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001067 public boolean isInterruptive() {
1068 return mIsInterruptive;
1069 }
1070
Gus Prevas7306b902018-12-11 10:57:06 -05001071 /** Returns the time the notification audibly alerted the user. */
1072 public long getLastAudiblyAlertedMs() {
1073 return mLastAudiblyAlertedMs;
Gus Prevasa3226492018-10-23 11:10:09 -04001074 }
1075
Julia Reynolds22f02b32016-12-01 15:05:13 -05001076 protected void setPeopleOverride(ArrayList<String> people) {
1077 mPeopleOverride = people;
1078 }
1079
1080 public ArrayList<SnoozeCriterion> getSnoozeCriteria() {
1081 return mSnoozeCriteria;
1082 }
1083
1084 protected void setSnoozeCriteria(ArrayList<SnoozeCriterion> snoozeCriteria) {
1085 mSnoozeCriteria = snoozeCriteria;
1086 }
Chris Wren9eb5e102017-01-26 13:15:06 -05001087
Julia Reynoldsc65656a2018-02-12 09:55:14 -05001088 private void calculateUserSentiment() {
Rohan Shah590e1b22018-04-10 23:48:47 -04001089 if ((getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0
1090 || mIsAppImportanceLocked) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -05001091 mUserSentiment = USER_SENTIMENT_POSITIVE;
1092 }
1093 }
1094
Julia Reynolds503ed942017-10-04 16:04:56 -04001095 private void setUserSentiment(int userSentiment) {
1096 mUserSentiment = userSentiment;
1097 }
1098
1099 public int getUserSentiment() {
1100 return mUserSentiment;
1101 }
1102
1103 public NotificationStats getStats() {
1104 return mStats;
1105 }
1106
1107 public void recordExpanded() {
1108 mStats.setExpanded();
1109 }
1110
1111 public void recordDirectReplied() {
1112 mStats.setDirectReplied();
1113 }
1114
1115 public void recordDismissalSurface(@NotificationStats.DismissalSurface int surface) {
1116 mStats.setDismissalSurface(surface);
1117 }
1118
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04001119 public void recordDismissalSentiment(@NotificationStats.DismissalSentiment int sentiment) {
1120 mStats.setDismissalSentiment(sentiment);
1121 }
1122
Julia Reynolds503ed942017-10-04 16:04:56 -04001123 public void recordSnoozed() {
1124 mStats.setSnoozed();
1125 }
1126
1127 public void recordViewedSettings() {
1128 mStats.setViewedSettings();
1129 }
1130
Kenny Guy23991102018-04-05 21:18:38 +01001131 public void setNumSmartRepliesAdded(int noReplies) {
1132 mNumberOfSmartRepliesAdded = noReplies;
1133 }
1134
1135 public int getNumSmartRepliesAdded() {
1136 return mNumberOfSmartRepliesAdded;
1137 }
1138
Gustav Senntond25a64d2018-12-07 10:58:39 +00001139 public void setNumSmartActionsAdded(int noActions) {
1140 mNumberOfSmartActionsAdded = noActions;
1141 }
1142
1143 public int getNumSmartActionsAdded() {
1144 return mNumberOfSmartActionsAdded;
1145 }
1146
1147 public void setSuggestionsGeneratedByAssistant(boolean generatedByAssistant) {
1148 mSuggestionsGeneratedByAssistant = generatedByAssistant;
1149 }
1150
1151 public boolean getSuggestionsGeneratedByAssistant() {
1152 return mSuggestionsGeneratedByAssistant;
1153 }
1154
Milo Sredkov13d88112019-02-01 12:23:24 +00001155 public boolean getEditChoicesBeforeSending() {
1156 return mEditChoicesBeforeSending;
1157 }
1158
1159 public void setEditChoicesBeforeSending(boolean editChoicesBeforeSending) {
1160 mEditChoicesBeforeSending = editChoicesBeforeSending;
1161 }
1162
Kenny Guy23991102018-04-05 21:18:38 +01001163 public boolean hasSeenSmartReplies() {
1164 return mHasSeenSmartReplies;
1165 }
1166
1167 public void setSeenSmartReplies(boolean hasSeenSmartReplies) {
1168 mHasSeenSmartReplies = hasSeenSmartReplies;
1169 }
1170
Gustav Sennton44dc5882018-12-13 14:38:50 +00001171 /**
1172 * Returns whether this notification has been visible and expanded at the same time.
1173 */
1174 public boolean hasBeenVisiblyExpanded() {
1175 return stats.hasBeenVisiblyExpanded();
1176 }
1177
Gustav Sennton1463d832018-11-06 16:12:48 +00001178 public void setSystemGeneratedSmartActions(
1179 ArrayList<Notification.Action> systemGeneratedSmartActions) {
1180 mSystemGeneratedSmartActions = systemGeneratedSmartActions;
Tony Mak628cb932018-06-19 18:30:41 +01001181 }
1182
Gustav Sennton1463d832018-11-06 16:12:48 +00001183 public ArrayList<Notification.Action> getSystemGeneratedSmartActions() {
1184 return mSystemGeneratedSmartActions;
Tony Mak628cb932018-06-19 18:30:41 +01001185 }
1186
Tony Makc9acf672018-07-20 13:58:24 +02001187 public void setSmartReplies(ArrayList<CharSequence> smartReplies) {
1188 mSmartReplies = smartReplies;
1189 }
1190
1191 public ArrayList<CharSequence> getSmartReplies() {
1192 return mSmartReplies;
1193 }
1194
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001195 /**
Julia Reynolds95334132018-12-19 11:15:35 -05001196 * Returns whether this notification was posted by a secondary app
1197 */
1198 public boolean isProxied() {
1199 return !Objects.equals(sbn.getPackageName(), sbn.getOpPkg());
1200 }
1201
1202 /**
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001203 * @return all {@link Uri} that should have permission granted to whoever
1204 * will be rendering it. This list has already been vetted to only
1205 * include {@link Uri} that the enqueuing app can grant.
1206 */
1207 public @Nullable ArraySet<Uri> getGrantableUris() {
1208 return mGrantableUris;
1209 }
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001210
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001211 /**
1212 * Collect all {@link Uri} that should have permission granted to whoever
1213 * will be rendering it.
1214 */
Julia Reynolds218871e2018-06-13 10:45:21 -04001215 protected void calculateGrantableUris() {
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001216 final Notification notification = getNotification();
Jeff Sharkey23b31182018-04-18 21:32:12 -06001217 notification.visitUris((uri) -> {
Julia Reynolds218871e2018-06-13 10:45:21 -04001218 visitGrantableUri(uri, false);
Jeff Sharkey23b31182018-04-18 21:32:12 -06001219 });
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001220
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001221 if (notification.getChannelId() != null) {
1222 NotificationChannel channel = getChannel();
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001223 if (channel != null) {
Julia Reynolds218871e2018-06-13 10:45:21 -04001224 visitGrantableUri(channel.getSound(), (channel.getUserLockedFields()
1225 & NotificationChannel.USER_LOCKED_SOUND) != 0);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001226 }
1227 }
1228 }
1229
1230 /**
1231 * Note the presence of a {@link Uri} that should have permission granted to
1232 * whoever will be rendering it.
1233 * <p>
1234 * If the enqueuing app has the ability to grant access, it will be added to
1235 * {@link #mGrantableUris}. Otherwise, this will either log or throw
1236 * {@link SecurityException} depending on target SDK of enqueuing app.
1237 */
Julia Reynolds218871e2018-06-13 10:45:21 -04001238 private void visitGrantableUri(Uri uri, boolean userOverriddenUri) {
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001239 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
1240
1241 // We can't grant Uri permissions from system
1242 final int sourceUid = sbn.getUid();
1243 if (sourceUid == android.os.Process.SYSTEM_UID) return;
1244
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001245 final long ident = Binder.clearCallingIdentity();
1246 try {
1247 // This will throw SecurityException if caller can't grant
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001248 mUgmInternal.checkGrantUriPermission(sourceUid, null,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001249 ContentProvider.getUriWithoutUserId(uri),
1250 Intent.FLAG_GRANT_READ_URI_PERMISSION,
1251 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
1252
1253 if (mGrantableUris == null) {
1254 mGrantableUris = new ArraySet<>();
1255 }
1256 mGrantableUris.add(uri);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001257 } catch (SecurityException e) {
Julia Reynolds218871e2018-06-13 10:45:21 -04001258 if (!userOverriddenUri) {
1259 if (mTargetSdkVersion >= Build.VERSION_CODES.P) {
1260 throw e;
1261 } else {
1262 Log.w(TAG, "Ignoring " + uri + " from " + sourceUid + ": " + e.getMessage());
1263 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001264 }
1265 } finally {
1266 Binder.restoreCallingIdentity(ident);
1267 }
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001268 }
1269
Chris Wren9eb5e102017-01-26 13:15:06 -05001270 public LogMaker getLogMaker(long now) {
Will Brockman934b8e32019-03-08 11:14:45 -05001271 LogMaker lm = sbn.getLogMaker()
Chris Wrenb3921792017-06-01 13:34:46 -04001272 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance)
Chris Wren9eb5e102017-01-26 13:15:06 -05001273 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now))
1274 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now))
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -04001275 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now))
1276 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS,
1277 getInterruptionMs(now));
Will Brockman934b8e32019-03-08 11:14:45 -05001278 // Record results of the calculateImportance() calculation if available.
1279 if (mImportanceExplanationCode != MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN) {
1280 lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION,
1281 mImportanceExplanationCode);
1282 // To avoid redundancy, we log the initial importance information only if it was
1283 // overridden.
1284 if (((mImportanceExplanationCode == MetricsEvent.IMPORTANCE_EXPLANATION_ASST)
1285 || (mImportanceExplanationCode == MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM))
1286 && (stats.naturalImportance != IMPORTANCE_UNSPECIFIED)) {
1287 // stats.naturalImportance is due to one of the 3 sources of initial importance.
1288 lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION,
1289 mInitialImportanceExplanationCode);
1290 lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL,
1291 stats.naturalImportance);
1292 }
1293 // Log Assistant override if it was itself overridden by System. Since System can't be
1294 // overridden, it never needs logging.
1295 if (mImportanceExplanationCode == MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM
1296 && mAssistantImportance != IMPORTANCE_UNSPECIFIED) {
1297 lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST,
1298 mAssistantImportance);
1299 }
1300 }
1301 return lm;
Chris Wren9eb5e102017-01-26 13:15:06 -05001302 }
1303
1304 public LogMaker getLogMaker() {
1305 return getLogMaker(System.currentTimeMillis());
1306 }
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05001307
Julia Reynolds3dfdde02018-10-08 09:17:56 -04001308 public LogMaker getItemLogMaker() {
1309 return getLogMaker().setCategory(MetricsEvent.NOTIFICATION_ITEM);
1310 }
1311
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05001312 @VisibleForTesting
1313 static final class Light {
1314 public final int color;
1315 public final int onMs;
1316 public final int offMs;
1317
1318 public Light(int color, int onMs, int offMs) {
1319 this.color = color;
1320 this.onMs = onMs;
1321 this.offMs = offMs;
1322 }
1323
1324 @Override
1325 public boolean equals(Object o) {
1326 if (this == o) return true;
1327 if (o == null || getClass() != o.getClass()) return false;
1328
1329 Light light = (Light) o;
1330
1331 if (color != light.color) return false;
1332 if (onMs != light.onMs) return false;
1333 return offMs == light.offMs;
1334
1335 }
1336
1337 @Override
1338 public int hashCode() {
1339 int result = color;
1340 result = 31 * result + onMs;
1341 result = 31 * result + offMs;
1342 return result;
1343 }
1344
1345 @Override
1346 public String toString() {
1347 return "Light{" +
1348 "color=" + color +
1349 ", onMs=" + onMs +
1350 ", offMs=" + offMs +
1351 '}';
1352 }
1353 }
Chris Wren333a61c2014-05-28 16:40:57 -04001354}