blob: a11b03f6866702d435cb781539ac804ecf095fcd [file] [log] [blame]
Chris Wren333a61c2014-05-28 16:40:57 -04001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.server.notification;
17
Julia Reynoldsc65656a2018-02-12 09:55:14 -050018import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
Julia Reynolds85769912016-10-25 09:08:57 -040019import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
20import static android.app.NotificationManager.IMPORTANCE_HIGH;
21import static android.app.NotificationManager.IMPORTANCE_LOW;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060022import static android.app.NotificationManager.IMPORTANCE_MIN;
23import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
Julia Reynolds503ed942017-10-04 16:04:56 -040024import static android.service.notification.NotificationListenerService.Ranking
25 .USER_SENTIMENT_NEUTRAL;
Julia Reynoldsc65656a2018-02-12 09:55:14 -050026import static android.service.notification.NotificationListenerService.Ranking
27 .USER_SENTIMENT_POSITIVE;
Chris Wrenbdf33762015-12-04 15:50:51 -050028
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060029import android.annotation.Nullable;
30import android.app.ActivityManager;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060031import android.app.IActivityManager;
Chris Wren333a61c2014-05-28 16:40:57 -040032import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040033import android.app.NotificationChannel;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060034import android.content.ContentProvider;
35import android.content.ContentResolver;
Chris Wren333a61c2014-05-28 16:40:57 -040036import android.content.Context;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060037import android.content.Intent;
Tony Mantlerab55f0f2017-06-16 10:50:00 -070038import android.content.pm.PackageManager;
Chris Wren333a61c2014-05-28 16:40:57 -040039import android.content.pm.PackageManager.NameNotFoundException;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060040import android.content.pm.PackageManagerInternal;
Chris Wren333a61c2014-05-28 16:40:57 -040041import android.content.res.Resources;
42import android.graphics.Bitmap;
Dan Sandlerd63f9322015-05-06 15:18:49 -040043import android.graphics.drawable.Icon;
John Spurlockbfa5dc42014-07-28 23:30:45 -040044import android.media.AudioAttributes;
Julia Reynolds0c299d42016-11-15 14:37:04 -050045import android.media.AudioSystem;
Chris Wren9eb5e102017-01-26 13:15:06 -050046import android.metrics.LogMaker;
Julia Reynolds0c299d42016-11-15 14:37:04 -050047import android.net.Uri;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060048import android.os.Binder;
Julia Reynolds0c299d42016-11-15 14:37:04 -050049import android.os.Build;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040050import android.os.Bundle;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060051import android.os.IBinder;
Chris Wrenda4bd202014-09-04 15:53:52 -040052import android.os.UserHandle;
Julia Reynolds0c299d42016-11-15 14:37:04 -050053import android.provider.Settings;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040054import android.service.notification.Adjustment;
Julia Reynolds5d25ee72015-11-20 15:38:20 -050055import android.service.notification.NotificationListenerService;
Julia Reynoldsc9842c12017-02-07 12:46:41 -050056import android.service.notification.NotificationRecordProto;
Julia Reynolds503ed942017-10-04 16:04:56 -040057import android.service.notification.NotificationStats;
Julia Reynolds22f02b32016-12-01 15:05:13 -050058import android.service.notification.SnoozeCriterion;
Chris Wren333a61c2014-05-28 16:40:57 -040059import android.service.notification.StatusBarNotification;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -050060import android.text.TextUtils;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040061import android.util.ArraySet;
Julia Reynoldsf0f629f2016-02-25 09:34:04 -050062import android.util.Log;
Julia Reynolds2a128742016-11-28 14:29:25 -050063import android.util.TimeUtils;
Julia Reynoldsc9842c12017-02-07 12:46:41 -050064import android.util.proto.ProtoOutputStream;
Dan Sandler0a2308e2017-05-30 19:50:42 -040065import android.widget.RemoteViews;
John Spurlockbfa5dc42014-07-28 23:30:45 -040066
Chris Wren1031c972014-07-23 13:11:45 +000067import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -050068import com.android.internal.logging.MetricsLogger;
69import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Chris Wren6650e572015-05-15 17:19:25 -040070import com.android.server.EventLogTags;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -060071import com.android.server.LocalServices;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070072import com.android.server.uri.UriGrantsManagerInternal;
Chris Wren333a61c2014-05-28 16:40:57 -040073
74import java.io.PrintWriter;
75import java.lang.reflect.Array;
Julia Reynolds22f02b32016-12-01 15:05:13 -050076import java.util.ArrayList;
Chris Wren333a61c2014-05-28 16:40:57 -040077import java.util.Arrays;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040078import java.util.List;
John Spurlock312d1d02014-07-08 10:24:57 -040079import java.util.Objects;
Chris Wren333a61c2014-05-28 16:40:57 -040080
81/**
82 * Holds data about notifications that should not be shared with the
83 * {@link android.service.notification.NotificationListenerService}s.
84 *
85 * <p>These objects should not be mutated unless the code is synchronized
Julia Reynolds88860ce2017-06-01 16:55:49 -040086 * on {@link NotificationManagerService#mNotificationLock}, and any
Chris Wren333a61c2014-05-28 16:40:57 -040087 * modification should be followed by a sorting of that list.</p>
88 *
89 * <p>Is sortable by {@link NotificationComparator}.</p>
90 *
91 * {@hide}
92 */
93public final class NotificationRecord {
Julia Reynoldsf0f629f2016-02-25 09:34:04 -050094 static final String TAG = "NotificationRecord";
95 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Chris Wrenb3921792017-06-01 13:34:46 -040096 private static final int MAX_LOGTAG_LENGTH = 35;
Chris Wren333a61c2014-05-28 16:40:57 -040097 final StatusBarNotification sbn;
Julia Reynolds218871e2018-06-13 10:45:21 -040098 IActivityManager mAm;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070099 UriGrantsManagerInternal mUgmInternal;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600100 final int mTargetSdkVersion;
Christoph Studer365e4c32014-09-18 20:35:36 +0200101 final int mOriginalFlags;
Chris Wrenbdf33762015-12-04 15:50:51 -0500102 private final Context mContext;
Christoph Studer365e4c32014-09-18 20:35:36 +0200103
Chris Wren333a61c2014-05-28 16:40:57 -0400104 NotificationUsageStats.SingleNotificationStats stats;
105 boolean isCanceled;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600106 IBinder permissionOwner;
Chris Wren333a61c2014-05-28 16:40:57 -0400107
108 // These members are used by NotificationSignalExtractors
109 // to communicate with the ranking module.
110 private float mContactAffinity;
111 private boolean mRecentlyIntrusive;
Julia Reynolds309d1c82017-05-03 16:00:20 -0400112 private long mLastIntrusive;
Chris Wren333a61c2014-05-28 16:40:57 -0400113
114 // is this notification currently being intercepted by Zen Mode?
115 private boolean mIntercept;
Chris Wren333a61c2014-05-28 16:40:57 -0400116
Beverly5a20a5e2018-03-06 15:02:44 -0500117 // is this notification hidden since the app pkg is suspended?
118 private boolean mHidden;
119
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200120 // The timestamp used for ranking.
121 private long mRankingTimeMs;
122
Chris Wren640e3872015-04-21 13:23:18 -0400123 // The first post time, stable across updates.
124 private long mCreationTimeMs;
125
Chris Wren6650e572015-05-15 17:19:25 -0400126 // The most recent visibility event.
127 private long mVisibleSinceMs;
128
129 // The most recent update time, or the creation time if no updates.
130 private long mUpdateTimeMs;
131
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
Chris Wrena3446562014-06-03 18:11:47 -0400137 // Is this record an update of an old record?
138 public boolean isUpdate;
Chris Wren54bbef42014-07-09 18:37:56 -0400139 private int mPackagePriority;
Chris Wrena3446562014-06-03 18:11:47 -0400140
Chris Wren1031c972014-07-23 13:11:45 +0000141 private int mAuthoritativeRank;
Christoph Studercd4adf82014-08-19 17:50:49 +0200142 private String mGlobalSortKey;
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400143 private int mPackageVisibility;
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400144 private int mSystemImportance = IMPORTANCE_UNSPECIFIED;
145 private int mAssistantImportance = IMPORTANCE_UNSPECIFIED;
Chris Wren47633422016-01-22 09:56:59 -0500146 private int mImportance = IMPORTANCE_UNSPECIFIED;
Brad Stenning9a8b2c82018-08-03 14:14:26 -0700147 // Field used in global sort key to bypass normal notifications
148 private int mCriticality = CriticalNotificationExtractor.NORMAL;
Chris Wrenbdf33762015-12-04 15:50:51 -0500149 private CharSequence mImportanceExplanation = null;
Chris Wren1031c972014-07-23 13:11:45 +0000150
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500151 private int mSuppressedVisualEffects = 0;
Julia Reynoldsef37f282016-02-12 09:11:27 -0500152 private String mUserExplanation;
Chris Wrenbdf33762015-12-04 15:50:51 -0500153 private String mPeopleExplanation;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000154 private boolean mPreChannelsNotification = true;
Julia Reynolds0c299d42016-11-15 14:37:04 -0500155 private Uri mSound;
156 private long[] mVibration;
157 private AudioAttributes mAttributes;
Julia Reynolds924eed12017-01-19 09:52:07 -0500158 private NotificationChannel mChannel;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500159 private ArrayList<String> mPeopleOverride;
160 private ArrayList<SnoozeCriterion> mSnoozeCriteria;
Julia Reynolds924eed12017-01-19 09:52:07 -0500161 private boolean mShowBadge;
Chris Wren9eb5e102017-01-26 13:15:06 -0500162 private LogMaker mLogMaker;
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500163 private Light mLight;
Chris Wrenb3921792017-06-01 13:34:46 -0400164 private String mGroupLogTag;
165 private String mChannelIdLogTag;
Tony Mak628cb932018-06-19 18:30:41 +0100166 private ArrayList<Notification.Action> mSmartActions;
Tony Makc9acf672018-07-20 13:58:24 +0200167 private ArrayList<CharSequence> mSmartReplies;
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500168
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400169 private final List<Adjustment> mAdjustments;
Julia Reynolds503ed942017-10-04 16:04:56 -0400170 private final NotificationStats mStats;
171 private int mUserSentiment;
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500172 private boolean mIsInterruptive;
Gus Prevasa3226492018-10-23 11:10:09 -0400173 private boolean mAudiblyAlerted;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400174 private boolean mTextChanged;
175 private boolean mRecordedInterruption;
Kenny Guy23991102018-04-05 21:18:38 +0100176 private int mNumberOfSmartRepliesAdded;
177 private boolean mHasSeenSmartReplies;
Rohan Shah590e1b22018-04-10 23:48:47 -0400178 /**
179 * Whether this notification (and its channels) should be considered user locked. Used in
180 * conjunction with user sentiment calculation.
181 */
182 private boolean mIsAppImportanceLocked;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600183 private ArraySet<Uri> mGrantableUris;
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400184
Julia Reynolds924eed12017-01-19 09:52:07 -0500185 public NotificationRecord(Context context, StatusBarNotification sbn,
Rohan Shah590e1b22018-04-10 23:48:47 -0400186 NotificationChannel channel) {
Chris Wren333a61c2014-05-28 16:40:57 -0400187 this.sbn = sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600188 mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class)
189 .getPackageTargetSdkVersion(sbn.getPackageName());
Julia Reynolds218871e2018-06-13 10:45:21 -0400190 mAm = ActivityManager.getService();
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700191 mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
Christoph Studer365e4c32014-09-18 20:35:36 +0200192 mOriginalFlags = sbn.getNotification().flags;
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200193 mRankingTimeMs = calculateRankingTimeMs(0L);
Chris Wren640e3872015-04-21 13:23:18 -0400194 mCreationTimeMs = sbn.getPostTime();
Chris Wren6650e572015-05-15 17:19:25 -0400195 mUpdateTimeMs = mCreationTimeMs;
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400196 mInterruptionTimeMs = mCreationTimeMs;
Chris Wrenbdf33762015-12-04 15:50:51 -0500197 mContext = context;
Chris Wrencdee8cd2016-01-25 17:10:30 -0500198 stats = new NotificationUsageStats.SingleNotificationStats();
Julia Reynolds924eed12017-01-19 09:52:07 -0500199 mChannel = channel;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000200 mPreChannelsNotification = isPreChannelsNotification();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500201 mSound = calculateSound();
202 mVibration = calculateVibration();
203 mAttributes = calculateAttributes();
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400204 mImportance = calculateInitialImportance();
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500205 mLight = calculateLights();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400206 mAdjustments = new ArrayList<>();
Julia Reynolds503ed942017-10-04 16:04:56 -0400207 mStats = new NotificationStats();
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500208 calculateUserSentiment();
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600209 calculateGrantableUris();
Chris Wrenbdf33762015-12-04 15:50:51 -0500210 }
211
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000212 private boolean isPreChannelsNotification() {
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600213 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) {
214 if (mTargetSdkVersion < Build.VERSION_CODES.O) {
215 return true;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000216 }
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000217 }
218 return false;
219 }
220
Julia Reynolds0c299d42016-11-15 14:37:04 -0500221 private Uri calculateSound() {
Chris Wrenbdf33762015-12-04 15:50:51 -0500222 final Notification n = sbn.getNotification();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500223
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700224 // No notification sounds on tv
225 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
226 return null;
227 }
228
Julia Reynolds924eed12017-01-19 09:52:07 -0500229 Uri sound = mChannel.getSound();
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000230 if (mPreChannelsNotification && (getChannel().getUserLockedFields()
Julia Reynolds0c299d42016-11-15 14:37:04 -0500231 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
232
233 final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0;
234 if (useDefaultSound) {
235 sound = Settings.System.DEFAULT_NOTIFICATION_URI;
Julia Reynoldsb9e712e2017-04-17 10:31:03 -0400236 } else {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500237 sound = n.sound;
238 }
239 }
240 return sound;
241 }
242
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500243 private Light calculateLights() {
244 int defaultLightColor = mContext.getResources().getColor(
245 com.android.internal.R.color.config_defaultNotificationColor);
246 int defaultLightOn = mContext.getResources().getInteger(
247 com.android.internal.R.integer.config_defaultNotificationLedOn);
248 int defaultLightOff = mContext.getResources().getInteger(
249 com.android.internal.R.integer.config_defaultNotificationLedOff);
250
Julia Reynolds529e3322017-02-06 08:33:01 -0500251 int channelLightColor = getChannel().getLightColor() != 0 ? getChannel().getLightColor()
252 : defaultLightColor;
253 Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500254 defaultLightOn, defaultLightOff) : null;
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000255 if (mPreChannelsNotification
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500256 && (getChannel().getUserLockedFields()
257 & NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
258 final Notification notification = sbn.getNotification();
259 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
260 light = new Light(notification.ledARGB, notification.ledOnMS,
261 notification.ledOffMS);
262 if ((notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
263 light = new Light(defaultLightColor, defaultLightOn,
264 defaultLightOff);
265 }
266 } else {
267 light = null;
268 }
269 }
270 return light;
271 }
272
Julia Reynolds0c299d42016-11-15 14:37:04 -0500273 private long[] calculateVibration() {
274 long[] vibration;
275 final long[] defaultVibration = NotificationManagerService.getLongArray(
276 mContext.getResources(),
277 com.android.internal.R.array.config_defaultNotificationVibePattern,
278 NotificationManagerService.VIBRATE_PATTERN_MAXLEN,
279 NotificationManagerService.DEFAULT_VIBRATE_PATTERN);
280 if (getChannel().shouldVibrate()) {
Julia Reynoldsf57de462016-11-23 11:31:46 -0500281 vibration = getChannel().getVibrationPattern() == null
282 ? defaultVibration : getChannel().getVibrationPattern();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500283 } else {
284 vibration = null;
285 }
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000286 if (mPreChannelsNotification
Julia Reynolds0c299d42016-11-15 14:37:04 -0500287 && (getChannel().getUserLockedFields()
288 & NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
289 final Notification notification = sbn.getNotification();
290 final boolean useDefaultVibrate =
291 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
292 if (useDefaultVibrate) {
293 vibration = defaultVibration;
294 } else {
295 vibration = notification.vibrate;
296 }
297 }
298 return vibration;
299 }
300
301 private AudioAttributes calculateAttributes() {
302 final Notification n = sbn.getNotification();
Julia Reynolds619a69f2017-01-27 15:11:38 -0500303 AudioAttributes attributes = getChannel().getAudioAttributes();
304 if (attributes == null) {
305 attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
306 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500307
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000308 if (mPreChannelsNotification
Julia Reynolds619a69f2017-01-27 15:11:38 -0500309 && (getChannel().getUserLockedFields()
310 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
311 if (n.audioAttributes != null) {
312 // prefer audio attributes to stream type
313 attributes = n.audioAttributes;
314 } else if (n.audioStreamType >= 0
315 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
316 // the stream type is valid, use it
317 attributes = new AudioAttributes.Builder()
318 .setInternalLegacyStreamType(n.audioStreamType)
319 .build();
320 } else if (n.audioStreamType != AudioSystem.STREAM_DEFAULT) {
321 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
322 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500323 }
324 return attributes;
325 }
326
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400327 private int calculateInitialImportance() {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500328 final Notification n = sbn.getNotification();
329 int importance = getChannel().getImportance();
330 int requestedImportance = IMPORTANCE_DEFAULT;
Chris Wrenbdf33762015-12-04 15:50:51 -0500331
332 // Migrate notification flags to scores
333 if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) {
334 n.priority = Notification.PRIORITY_MAX;
335 }
336
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500337 n.priority = NotificationManagerService.clamp(n.priority, Notification.PRIORITY_MIN,
338 Notification.PRIORITY_MAX);
Chris Wrenbdf33762015-12-04 15:50:51 -0500339 switch (n.priority) {
340 case Notification.PRIORITY_MIN:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500341 requestedImportance = IMPORTANCE_MIN;
Julia Reynoldsf0f629f2016-02-25 09:34:04 -0500342 break;
Chris Wrenbdf33762015-12-04 15:50:51 -0500343 case Notification.PRIORITY_LOW:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500344 requestedImportance = IMPORTANCE_LOW;
Chris Wrenbdf33762015-12-04 15:50:51 -0500345 break;
346 case Notification.PRIORITY_DEFAULT:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500347 requestedImportance = IMPORTANCE_DEFAULT;
Chris Wrenbdf33762015-12-04 15:50:51 -0500348 break;
349 case Notification.PRIORITY_HIGH:
Chris Wrenbdf33762015-12-04 15:50:51 -0500350 case Notification.PRIORITY_MAX:
Julia Reynolds0c299d42016-11-15 14:37:04 -0500351 requestedImportance = IMPORTANCE_HIGH;
Chris Wrenbdf33762015-12-04 15:50:51 -0500352 break;
353 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500354 stats.requestedImportance = requestedImportance;
355 stats.isNoisy = mSound != null || mVibration != null;
Chris Wrenbdf33762015-12-04 15:50:51 -0500356
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000357 if (mPreChannelsNotification
Julia Reynoldsa917a112017-03-21 11:09:14 -0400358 && (importance == IMPORTANCE_UNSPECIFIED
359 || (getChannel().getUserLockedFields()
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500360 & USER_LOCKED_IMPORTANCE) == 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500361 if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) {
362 requestedImportance = IMPORTANCE_LOW;
Julia Reynolds83fa1072016-02-17 09:10:19 -0500363 }
Julia Reynolds83fa1072016-02-17 09:10:19 -0500364
Julia Reynolds0c299d42016-11-15 14:37:04 -0500365 if (stats.isNoisy) {
366 if (requestedImportance < IMPORTANCE_DEFAULT) {
367 requestedImportance = IMPORTANCE_DEFAULT;
368 }
369 }
370
371 if (n.fullScreenIntent != null) {
372 requestedImportance = IMPORTANCE_HIGH;
373 }
374 importance = requestedImportance;
Chris Wrenbdf33762015-12-04 15:50:51 -0500375 }
376
Chris Wrencdee8cd2016-01-25 17:10:30 -0500377 stats.naturalImportance = importance;
Chris Wrenbdf33762015-12-04 15:50:51 -0500378 return importance;
Chris Wren333a61c2014-05-28 16:40:57 -0400379 }
380
381 // copy any notes that the ranking system may have made before the update
382 public void copyRankingInformation(NotificationRecord previous) {
383 mContactAffinity = previous.mContactAffinity;
384 mRecentlyIntrusive = previous.mRecentlyIntrusive;
Chris Wren54bbef42014-07-09 18:37:56 -0400385 mPackagePriority = previous.mPackagePriority;
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400386 mPackageVisibility = previous.mPackageVisibility;
Chris Wren333a61c2014-05-28 16:40:57 -0400387 mIntercept = previous.mIntercept;
Beverly5a20a5e2018-03-06 15:02:44 -0500388 mHidden = previous.mHidden;
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200389 mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
Chris Wren640e3872015-04-21 13:23:18 -0400390 mCreationTimeMs = previous.mCreationTimeMs;
Chris Wren6650e572015-05-15 17:19:25 -0400391 mVisibleSinceMs = previous.mVisibleSinceMs;
Selim Cinek5b03ce92016-05-18 15:16:58 -0700392 if (previous.sbn.getOverrideGroupKey() != null && !sbn.isAppGroup()) {
Chris Wren8a1638f2016-05-02 16:19:14 -0400393 sbn.setOverrideGroupKey(previous.sbn.getOverrideGroupKey());
394 }
Chris Wren1f602dc2016-04-11 10:33:46 -0400395 // Don't copy importance information or mGlobalSortKey, recompute them.
Chris Wren333a61c2014-05-28 16:40:57 -0400396 }
397
398 public Notification getNotification() { return sbn.getNotification(); }
399 public int getFlags() { return sbn.getNotification().flags; }
Chris Wrenda4bd202014-09-04 15:53:52 -0400400 public UserHandle getUser() { return sbn.getUser(); }
Chris Wren333a61c2014-05-28 16:40:57 -0400401 public String getKey() { return sbn.getKey(); }
Chris Wrenda4bd202014-09-04 15:53:52 -0400402 /** @deprecated Use {@link #getUser()} instead. */
403 public int getUserId() { return sbn.getUserId(); }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -0600404 public int getUid() { return sbn.getUid(); }
Chris Wren333a61c2014-05-28 16:40:57 -0400405
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800406 void dump(ProtoOutputStream proto, long fieldId, boolean redact, int state) {
407 final long token = proto.start(fieldId);
408
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500409 proto.write(NotificationRecordProto.KEY, sbn.getKey());
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800410 proto.write(NotificationRecordProto.STATE, state);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500411 if (getChannel() != null) {
412 proto.write(NotificationRecordProto.CHANNEL_ID, getChannel().getId());
413 }
414 proto.write(NotificationRecordProto.CAN_SHOW_LIGHT, getLight() != null);
415 proto.write(NotificationRecordProto.CAN_VIBRATE, getVibration() != null);
416 proto.write(NotificationRecordProto.FLAGS, sbn.getNotification().flags);
417 proto.write(NotificationRecordProto.GROUP_KEY, getGroupKey());
418 proto.write(NotificationRecordProto.IMPORTANCE, getImportance());
419 if (getSound() != null) {
420 proto.write(NotificationRecordProto.SOUND, getSound().toString());
421 }
422 if (getAudioAttributes() != null) {
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800423 getAudioAttributes().writeToProto(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500424 }
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800425
426 proto.end(token);
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500427 }
428
Dan Sandler0a2308e2017-05-30 19:50:42 -0400429 String formatRemoteViews(RemoteViews rv) {
430 if (rv == null) return "null";
431 return String.format("%s/0x%08x (%d bytes): %s",
432 rv.getPackage(), rv.getLayoutId(), rv.estimateMemoryUsage(), rv.toString());
433 }
434
Dan Sandlera1770312015-07-10 13:59:29 -0400435 void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
Chris Wren333a61c2014-05-28 16:40:57 -0400436 final Notification notification = sbn.getNotification();
Dan Sandlerd63f9322015-05-06 15:18:49 -0400437 final Icon icon = notification.getSmallIcon();
438 String iconStr = String.valueOf(icon);
439 if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
440 iconStr += " / " + idDebugString(baseContext, icon.getResPackage(), icon.getResId());
441 }
Chris Wren333a61c2014-05-28 16:40:57 -0400442 pw.println(prefix + this);
Dan Sandler0a2308e2017-05-30 19:50:42 -0400443 prefix = prefix + " ";
Julia Reynoldsa917a112017-03-21 11:09:14 -0400444 pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
445 pw.println(prefix + "icon=" + iconStr);
Julia Reynolds4db59552017-06-30 13:34:01 -0400446 pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400447 pw.println(prefix + "pri=" + notification.priority);
448 pw.println(prefix + "key=" + sbn.getKey());
Julia Reynolds503ed942017-10-04 16:04:56 -0400449 pw.println(prefix + "seen=" + mStats.hasSeen());
Julia Reynoldsa917a112017-03-21 11:09:14 -0400450 pw.println(prefix + "groupKey=" + getGroupKey());
451 pw.println(prefix + "fullscreenIntent=" + notification.fullScreenIntent);
452 pw.println(prefix + "contentIntent=" + notification.contentIntent);
453 pw.println(prefix + "deleteIntent=" + notification.deleteIntent);
Aaron Heuckrothb4d6aa72018-07-02 14:58:33 -0400454 pw.println(prefix + "number=" + notification.number);
455 pw.println(prefix + "groupAlertBehavior=" + notification.getGroupAlertBehavior());
Dan Sandler0b4ceb32017-03-29 14:13:55 -0400456
457 pw.print(prefix + "tickerText=");
458 if (!TextUtils.isEmpty(notification.tickerText)) {
459 final String ticker = notification.tickerText.toString();
460 if (redact) {
461 // if the string is long enough, we allow ourselves a few bytes for debugging
462 pw.print(ticker.length() > 16 ? ticker.substring(0,8) : "");
463 pw.println("...");
464 } else {
465 pw.println(ticker);
466 }
467 } else {
468 pw.println("null");
469 }
Dan Sandler0a2308e2017-05-30 19:50:42 -0400470 pw.println(prefix + "contentView=" + formatRemoteViews(notification.contentView));
471 pw.println(prefix + "bigContentView=" + formatRemoteViews(notification.bigContentView));
472 pw.println(prefix + "headsUpContentView="
473 + formatRemoteViews(notification.headsUpContentView));
474 pw.print(prefix + String.format("color=0x%08x", notification.color));
Julia Reynoldsbad42972017-04-25 13:52:49 -0400475 pw.println(prefix + "timeout="
476 + TimeUtils.formatForLogging(notification.getTimeoutAfter()));
Chris Wren333a61c2014-05-28 16:40:57 -0400477 if (notification.actions != null && notification.actions.length > 0) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400478 pw.println(prefix + "actions={");
Chris Wren333a61c2014-05-28 16:40:57 -0400479 final int N = notification.actions.length;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500480 for (int i = 0; i < N; i++) {
Chris Wren333a61c2014-05-28 16:40:57 -0400481 final Notification.Action action = notification.actions[i];
Chris Wren1ac52a92016-02-24 14:54:52 -0500482 if (action != null) {
483 pw.println(String.format("%s [%d] \"%s\" -> %s",
484 prefix,
485 i,
486 action.title,
487 action.actionIntent == null ? "null" : action.actionIntent.toString()
488 ));
489 }
Chris Wren333a61c2014-05-28 16:40:57 -0400490 }
491 pw.println(prefix + " }");
492 }
493 if (notification.extras != null && notification.extras.size() > 0) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400494 pw.println(prefix + "extras={");
Chris Wren333a61c2014-05-28 16:40:57 -0400495 for (String key : notification.extras.keySet()) {
496 pw.print(prefix + " " + key + "=");
497 Object val = notification.extras.get(key);
498 if (val == null) {
499 pw.println("null");
500 } else {
501 pw.print(val.getClass().getSimpleName());
Dan Sandlera1770312015-07-10 13:59:29 -0400502 if (redact && (val instanceof CharSequence || val instanceof String)) {
Chris Wren333a61c2014-05-28 16:40:57 -0400503 // redact contents from bugreports
504 } else if (val instanceof Bitmap) {
505 pw.print(String.format(" (%dx%d)",
506 ((Bitmap) val).getWidth(),
507 ((Bitmap) val).getHeight()));
508 } else if (val.getClass().isArray()) {
509 final int N = Array.getLength(val);
Dan Sandlera1770312015-07-10 13:59:29 -0400510 pw.print(" (" + N + ")");
511 if (!redact) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500512 for (int j = 0; j < N; j++) {
Dan Sandlera1770312015-07-10 13:59:29 -0400513 pw.println();
514 pw.print(String.format("%s [%d] %s",
515 prefix, j, String.valueOf(Array.get(val, j))));
516 }
517 }
Chris Wren333a61c2014-05-28 16:40:57 -0400518 } else {
519 pw.print(" (" + String.valueOf(val) + ")");
520 }
521 pw.println();
522 }
523 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400524 pw.println(prefix + "}");
Chris Wren333a61c2014-05-28 16:40:57 -0400525 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400526 pw.println(prefix + "stats=" + stats.toString());
527 pw.println(prefix + "mContactAffinity=" + mContactAffinity);
528 pw.println(prefix + "mRecentlyIntrusive=" + mRecentlyIntrusive);
529 pw.println(prefix + "mPackagePriority=" + mPackagePriority);
530 pw.println(prefix + "mPackageVisibility=" + mPackageVisibility);
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400531 pw.println(prefix + "mSystemImportance="
532 + NotificationListenerService.Ranking.importanceToString(mSystemImportance));
533 pw.println(prefix + "mAsstImportance="
534 + NotificationListenerService.Ranking.importanceToString(mAssistantImportance));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400535 pw.println(prefix + "mImportance="
Chris Wrenbdf33762015-12-04 15:50:51 -0500536 + NotificationListenerService.Ranking.importanceToString(mImportance));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400537 pw.println(prefix + "mImportanceExplanation=" + mImportanceExplanation);
Rohan Shah590e1b22018-04-10 23:48:47 -0400538 pw.println(prefix + "mIsAppImportanceLocked=" + mIsAppImportanceLocked);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400539 pw.println(prefix + "mIntercept=" + mIntercept);
Beverly5a20a5e2018-03-06 15:02:44 -0500540 pw.println(prefix + "mHidden==" + mHidden);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400541 pw.println(prefix + "mGlobalSortKey=" + mGlobalSortKey);
542 pw.println(prefix + "mRankingTimeMs=" + mRankingTimeMs);
543 pw.println(prefix + "mCreationTimeMs=" + mCreationTimeMs);
544 pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
545 pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400546 pw.println(prefix + "mInterruptionTimeMs=" + mInterruptionTimeMs);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400547 pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
Geoffrey Pitscha22f6442017-05-05 16:47:38 +0000548 if (mPreChannelsNotification) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400549 pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500550 notification.defaults, notification.flags));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400551 pw.println(prefix + "n.sound=" + notification.sound);
552 pw.println(prefix + "n.audioStreamType=" + notification.audioStreamType);
553 pw.println(prefix + "n.audioAttributes=" + notification.audioAttributes);
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500554 pw.println(prefix + String.format(" led=0x%08x onMs=%d offMs=%d",
555 notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
Julia Reynoldsa917a112017-03-21 11:09:14 -0400556 pw.println(prefix + "vibrate=" + Arrays.toString(notification.vibrate));
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500557 }
Julia Reynoldsa917a112017-03-21 11:09:14 -0400558 pw.println(prefix + "mSound= " + mSound);
559 pw.println(prefix + "mVibration= " + mVibration);
560 pw.println(prefix + "mAttributes= " + mAttributes);
561 pw.println(prefix + "mLight= " + mLight);
562 pw.println(prefix + "mShowBadge=" + mShowBadge);
Julia Reynolds4db59552017-06-30 13:34:01 -0400563 pw.println(prefix + "mColorized=" + notification.isColorized());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500564 pw.println(prefix + "mIsInterruptive=" + mIsInterruptive);
Julia Reynoldsa917a112017-03-21 11:09:14 -0400565 pw.println(prefix + "effectiveNotificationChannel=" + getChannel());
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500566 if (getPeopleOverride() != null) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400567 pw.println(prefix + "overridePeople= " + TextUtils.join(",", getPeopleOverride()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500568 }
569 if (getSnoozeCriteria() != null) {
Julia Reynoldsa917a112017-03-21 11:09:14 -0400570 pw.println(prefix + "snoozeCriteria=" + TextUtils.join(",", getSnoozeCriteria()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500571 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400572 pw.println(prefix + "mAdjustments=" + mAdjustments);
Chris Wren333a61c2014-05-28 16:40:57 -0400573 }
574
575
576 static String idDebugString(Context baseContext, String packageName, int id) {
577 Context c;
578
579 if (packageName != null) {
580 try {
581 c = baseContext.createPackageContext(packageName, 0);
582 } catch (NameNotFoundException e) {
583 c = baseContext;
584 }
585 } else {
586 c = baseContext;
587 }
588
589 Resources r = c.getResources();
590 try {
591 return r.getResourceName(id);
592 } catch (Resources.NotFoundException e) {
593 return "<name unknown>";
594 }
595 }
596
597 @Override
598 public final String toString() {
599 return String.format(
Julia Reynolds85769912016-10-25 09:08:57 -0400600 "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s importance=%d key=%s" +
Rohan Shah590e1b22018-04-10 23:48:47 -0400601 "appImportanceLocked=%s: %s)",
Chris Wren333a61c2014-05-28 16:40:57 -0400602 System.identityHashCode(this),
603 this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(),
Julia Reynolds4db59552017-06-30 13:34:01 -0400604 this.sbn.getTag(), this.mImportance, this.sbn.getKey(),
Rohan Shah590e1b22018-04-10 23:48:47 -0400605 mIsAppImportanceLocked, this.sbn.getNotification());
Chris Wren333a61c2014-05-28 16:40:57 -0400606 }
607
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400608 public void addAdjustment(Adjustment adjustment) {
609 synchronized (mAdjustments) {
610 mAdjustments.add(adjustment);
611 }
612 }
613
614 public void applyAdjustments() {
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400615 long now = System.currentTimeMillis();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400616 synchronized (mAdjustments) {
617 for (Adjustment adjustment: mAdjustments) {
618 Bundle signals = adjustment.getSignals();
619 if (signals.containsKey(Adjustment.KEY_PEOPLE)) {
620 final ArrayList<String> people =
621 adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
622 setPeopleOverride(people);
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400623 MetricsLogger.action(getAdjustmentLogMaker()
624 .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_PEOPLE, people.size()));
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400625 }
626 if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) {
627 final ArrayList<SnoozeCriterion> snoozeCriterionList =
628 adjustment.getSignals().getParcelableArrayList(
629 Adjustment.KEY_SNOOZE_CRITERIA);
630 setSnoozeCriteria(snoozeCriterionList);
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400631 MetricsLogger.action(getAdjustmentLogMaker()
632 .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SNOOZE_CRITERIA,
633 snoozeCriterionList.size()));
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400634 }
635 if (signals.containsKey(Adjustment.KEY_GROUP_KEY)) {
636 final String groupOverrideKey =
637 adjustment.getSignals().getString(Adjustment.KEY_GROUP_KEY);
638 setOverrideGroupKey(groupOverrideKey);
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400639 MetricsLogger.action(getAdjustmentLogMaker()
640 .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_GROUP_KEY,
641 groupOverrideKey));
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400642 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400643 if (signals.containsKey(Adjustment.KEY_USER_SENTIMENT)) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500644 // Only allow user sentiment update from assistant if user hasn't already
645 // expressed a preference for this channel
Rohan Shah590e1b22018-04-10 23:48:47 -0400646 if (!mIsAppImportanceLocked
647 && (getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500648 setUserSentiment(adjustment.getSignals().getInt(
649 Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEUTRAL));
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400650 MetricsLogger.action(getAdjustmentLogMaker()
651 .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_USER_SENTIMENT,
652 getUserSentiment()));
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500653 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400654 }
Tony Mak628cb932018-06-19 18:30:41 +0100655 if (signals.containsKey(Adjustment.KEY_SMART_ACTIONS)) {
656 setSmartActions(signals.getParcelableArrayList(Adjustment.KEY_SMART_ACTIONS));
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400657 MetricsLogger.action(getAdjustmentLogMaker()
658 .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_ACTIONS,
659 getSmartActions().size()));
Tony Mak628cb932018-06-19 18:30:41 +0100660 }
Tony Makc9acf672018-07-20 13:58:24 +0200661 if (signals.containsKey(Adjustment.KEY_SMART_REPLIES)) {
662 setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES));
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400663 MetricsLogger.action(getAdjustmentLogMaker()
664 .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_REPLIES,
665 getSmartReplies().size()));
Tony Makc9acf672018-07-20 13:58:24 +0200666 }
Tony Mak8a8ddad2018-11-13 17:21:33 +0000667 }
668 applyImportanceFromAdjustments();
669 }
670 }
671
672 /**
673 * Update importance from the adjustment.
674 */
675 public void applyImportanceFromAdjustments() {
676 synchronized (mAdjustments) {
677 for (Adjustment adjustment : mAdjustments) {
678 Bundle signals = adjustment.getSignals();
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400679 if (signals.containsKey(Adjustment.KEY_IMPORTANCE)) {
680 int importance = signals.getInt(Adjustment.KEY_IMPORTANCE);
681 importance = Math.max(IMPORTANCE_UNSPECIFIED, importance);
682 importance = Math.min(IMPORTANCE_HIGH, importance);
683 setAssistantImportance(importance);
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400684 MetricsLogger.action(getAdjustmentLogMaker()
685 .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_IMPORTANCE,
686 importance));
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400687 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400688 }
689 }
690 }
691
Rohan Shah590e1b22018-04-10 23:48:47 -0400692 public void setIsAppImportanceLocked(boolean isAppImportanceLocked) {
693 mIsAppImportanceLocked = isAppImportanceLocked;
694 calculateUserSentiment();
695 }
696
Chris Wren333a61c2014-05-28 16:40:57 -0400697 public void setContactAffinity(float contactAffinity) {
698 mContactAffinity = contactAffinity;
699 }
700
701 public float getContactAffinity() {
702 return mContactAffinity;
703 }
704
John Spurlock1d881a12015-03-18 19:21:54 -0400705 public void setRecentlyIntrusive(boolean recentlyIntrusive) {
Chris Wren333a61c2014-05-28 16:40:57 -0400706 mRecentlyIntrusive = recentlyIntrusive;
Julia Reynolds309d1c82017-05-03 16:00:20 -0400707 if (recentlyIntrusive) {
708 mLastIntrusive = System.currentTimeMillis();
709 }
Chris Wren333a61c2014-05-28 16:40:57 -0400710 }
711
712 public boolean isRecentlyIntrusive() {
713 return mRecentlyIntrusive;
714 }
715
Julia Reynolds309d1c82017-05-03 16:00:20 -0400716 public long getLastIntrusive() {
717 return mLastIntrusive;
718 }
719
Chris Wren54bbef42014-07-09 18:37:56 -0400720 public void setPackagePriority(int packagePriority) {
John Spurlock6ac5f8d2014-07-18 11:27:54 -0400721 mPackagePriority = packagePriority;
Chris Wren54bbef42014-07-09 18:37:56 -0400722 }
723
724 public int getPackagePriority() {
725 return mPackagePriority;
726 }
727
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400728 public void setPackageVisibilityOverride(int packageVisibility) {
729 mPackageVisibility = packageVisibility;
730 }
731
732 public int getPackageVisibilityOverride() {
733 return mPackageVisibility;
734 }
735
Julia Reynoldsef37f282016-02-12 09:11:27 -0500736 private String getUserExplanation() {
737 if (mUserExplanation == null) {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500738 mUserExplanation = mContext.getResources().getString(
739 com.android.internal.R.string.importance_from_user);
Chris Wrenbdf33762015-12-04 15:50:51 -0500740 }
Julia Reynoldsef37f282016-02-12 09:11:27 -0500741 return mUserExplanation;
Chris Wrenbdf33762015-12-04 15:50:51 -0500742 }
743
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400744 /**
745 * Sets the importance value the system thinks the record should have.
746 * e.g. bumping up foreground service notifications or people to people notifications.
747 */
748 public void setSystemImportance(int importance) {
749 mSystemImportance = importance;
750 calculateImportance();
Chris Wrenbdf33762015-12-04 15:50:51 -0500751 }
752
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400753 /**
754 * Sets the importance value the
755 * {@link android.service.notification.NotificationAssistantService} thinks the record should
756 * have.
757 */
758 public void setAssistantImportance(int importance) {
759 mAssistantImportance = importance;
760 calculateImportance();
Julia Reynolds5d25ee72015-11-20 15:38:20 -0500761 }
762
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400763 /**
764 * Recalculates the importance of the record after fields affecting importance have changed
765 */
766 protected void calculateImportance() {
767 mImportance = calculateInitialImportance();
768 mImportanceExplanation = "app";
Julia Reynolds48a6ed92018-10-22 12:52:03 -0400769 if (getChannel().hasUserSetImportance()) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400770 mImportanceExplanation = "user";
Chris Wrenbdf33762015-12-04 15:50:51 -0500771 }
Julia Reynolds48a6ed92018-10-22 12:52:03 -0400772 if (!getChannel().hasUserSetImportance() && mAssistantImportance != IMPORTANCE_UNSPECIFIED) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400773 mImportance = mAssistantImportance;
774 mImportanceExplanation = "asst";
775 }
776 if (mSystemImportance != IMPORTANCE_UNSPECIFIED) {
777 mImportance = mSystemImportance;
778 mImportanceExplanation = "system";
779 }
Chris Wrenbdf33762015-12-04 15:50:51 -0500780 }
781
782 public int getImportance() {
783 return mImportance;
784 }
785
786 public CharSequence getImportanceExplanation() {
787 return mImportanceExplanation;
788 }
789
Chris Wren333a61c2014-05-28 16:40:57 -0400790 public boolean setIntercepted(boolean intercept) {
791 mIntercept = intercept;
792 return mIntercept;
793 }
794
Brad Stenning9a8b2c82018-08-03 14:14:26 -0700795 /**
796 * Set to affect global sort key.
797 *
798 * @param criticality used in a string based sort thus 0 is the most critical
799 */
800 public void setCriticality(int criticality) {
801 mCriticality = criticality;
802 }
803
804 public int getCriticality() {
805 return mCriticality;
806 }
807
Chris Wren333a61c2014-05-28 16:40:57 -0400808 public boolean isIntercepted() {
809 return mIntercept;
810 }
811
Beverly5a20a5e2018-03-06 15:02:44 -0500812 public void setHidden(boolean hidden) {
813 mHidden = hidden;
814 }
815
816 public boolean isHidden() {
817 return mHidden;
818 }
819
820
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500821 public void setSuppressedVisualEffects(int effects) {
822 mSuppressedVisualEffects = effects;
823 }
824
825 public int getSuppressedVisualEffects() {
826 return mSuppressedVisualEffects;
827 }
828
John Spurlock312d1d02014-07-08 10:24:57 -0400829 public boolean isCategory(String category) {
John Spurlockbfa5dc42014-07-28 23:30:45 -0400830 return Objects.equals(getNotification().category, category);
831 }
832
John Spurlockbfa5dc42014-07-28 23:30:45 -0400833 public boolean isAudioAttributesUsage(int usage) {
Julia Reynolds51eb78f82018-03-07 07:35:21 -0500834 return mAttributes != null && mAttributes.getUsage() == usage;
John Spurlock312d1d02014-07-08 10:24:57 -0400835 }
836
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200837 /**
838 * Returns the timestamp to use for time-based sorting in the ranker.
839 */
840 public long getRankingTimeMs() {
841 return mRankingTimeMs;
842 }
843
844 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400845 * @param now this current time in milliseconds.
846 * @returns the number of milliseconds since the most recent update, or the post time if none.
Chris Wren6650e572015-05-15 17:19:25 -0400847 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400848 public int getFreshnessMs(long now) {
849 return (int) (now - mUpdateTimeMs);
Chris Wren6650e572015-05-15 17:19:25 -0400850 }
851
852 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400853 * @param now this current time in milliseconds.
854 * @returns the number of milliseconds since the the first post, ignoring updates.
Chris Wren640e3872015-04-21 13:23:18 -0400855 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400856 public int getLifespanMs(long now) {
857 return (int) (now - mCreationTimeMs);
Chris Wren640e3872015-04-21 13:23:18 -0400858 }
859
860 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400861 * @param now this current time in milliseconds.
862 * @returns the number of milliseconds since the most recent visibility event, or 0 if never.
Chris Wren6650e572015-05-15 17:19:25 -0400863 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400864 public int getExposureMs(long now) {
865 return mVisibleSinceMs == 0 ? 0 : (int) (now - mVisibleSinceMs);
Chris Wren6650e572015-05-15 17:19:25 -0400866 }
867
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400868 public int getInterruptionMs(long now) {
869 return (int) (now - mInterruptionTimeMs);
870 }
871
Chris Wren6650e572015-05-15 17:19:25 -0400872 /**
873 * Set the visibility of the notification.
874 */
Dieter Hsud39f0d52018-04-14 02:08:30 +0800875 public void setVisibility(boolean visible, int rank, int count) {
Chris Wren6650e572015-05-15 17:19:25 -0400876 final long now = System.currentTimeMillis();
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400877 mVisibleSinceMs = visible ? now : mVisibleSinceMs;
Chris Wren6650e572015-05-15 17:19:25 -0400878 stats.onVisibilityChanged(visible);
Chris Wren9eb5e102017-01-26 13:15:06 -0500879 MetricsLogger.action(getLogMaker(now)
880 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
881 .setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800882 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
883 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count));
Chris Wren9eb5e102017-01-26 13:15:06 -0500884 if (visible) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400885 setSeen();
Chris Wren9eb5e102017-01-26 13:15:06 -0500886 MetricsLogger.histogram(mContext, "note_freshness", getFreshnessMs(now));
887 }
Chris Wren6650e572015-05-15 17:19:25 -0400888 EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0,
Chris Wren9eb5e102017-01-26 13:15:06 -0500889 getLifespanMs(now),
890 getFreshnessMs(now),
Chris Wrend1dbc922015-06-19 17:51:16 -0400891 0, // exposure time
892 rank);
Chris Wren6650e572015-05-15 17:19:25 -0400893 }
894
895 /**
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200896 * @param previousRankingTimeMs for updated notifications, {@link #getRankingTimeMs()}
897 * of the previous notification record, 0 otherwise
898 */
899 private long calculateRankingTimeMs(long previousRankingTimeMs) {
900 Notification n = getNotification();
901 // Take developer provided 'when', unless it's in the future.
902 if (n.when != 0 && n.when <= sbn.getPostTime()) {
903 return n.when;
904 }
905 // If we've ranked a previous instance with a timestamp, inherit it. This case is
906 // important in order to have ranking stability for updating notifications.
907 if (previousRankingTimeMs > 0) {
908 return previousRankingTimeMs;
909 }
910 return sbn.getPostTime();
911 }
Chris Wren1031c972014-07-23 13:11:45 +0000912
Christoph Studercd4adf82014-08-19 17:50:49 +0200913 public void setGlobalSortKey(String globalSortKey) {
914 mGlobalSortKey = globalSortKey;
Chris Wren1031c972014-07-23 13:11:45 +0000915 }
916
Christoph Studercd4adf82014-08-19 17:50:49 +0200917 public String getGlobalSortKey() {
918 return mGlobalSortKey;
Chris Wren1031c972014-07-23 13:11:45 +0000919 }
920
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700921 /** Check if any of the listeners have marked this notification as seen by the user. */
922 public boolean isSeen() {
Julia Reynolds503ed942017-10-04 16:04:56 -0400923 return mStats.hasSeen();
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700924 }
925
926 /** Mark the notification as seen by the user. */
927 public void setSeen() {
Julia Reynolds503ed942017-10-04 16:04:56 -0400928 mStats.setSeen();
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400929 if (mTextChanged) {
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -0400930 setInterruptive(true);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400931 }
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700932 }
933
Chris Wren1031c972014-07-23 13:11:45 +0000934 public void setAuthoritativeRank(int authoritativeRank) {
935 mAuthoritativeRank = authoritativeRank;
936 }
937
938 public int getAuthoritativeRank() {
939 return mAuthoritativeRank;
940 }
941
942 public String getGroupKey() {
943 return sbn.getGroupKey();
944 }
Chris Wren47633422016-01-22 09:56:59 -0500945
Chris Wrenb3921792017-06-01 13:34:46 -0400946 public void setOverrideGroupKey(String overrideGroupKey) {
947 sbn.setOverrideGroupKey(overrideGroupKey);
948 mGroupLogTag = null;
949 }
950
951 private String getGroupLogTag() {
952 if (mGroupLogTag == null) {
953 mGroupLogTag = shortenTag(sbn.getGroup());
954 }
955 return mGroupLogTag;
956 }
957
958 private String getChannelIdLogTag() {
959 if (mChannelIdLogTag == null) {
960 mChannelIdLogTag = shortenTag(mChannel.getId());
961 }
962 return mChannelIdLogTag;
963 }
964
965 private String shortenTag(String longTag) {
966 if (longTag == null) {
967 return null;
968 }
969 if (longTag.length() < MAX_LOGTAG_LENGTH) {
970 return longTag;
971 } else {
972 return longTag.substring(0, MAX_LOGTAG_LENGTH - 8) + "-" +
973 Integer.toHexString(longTag.hashCode());
974 }
975 }
976
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400977 public NotificationChannel getChannel() {
Julia Reynolds924eed12017-01-19 09:52:07 -0500978 return mChannel;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500979 }
980
Rohan Shah590e1b22018-04-10 23:48:47 -0400981 /**
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400982 * @see PreferencesHelper#getIsAppImportanceLocked(String, int)
Rohan Shah590e1b22018-04-10 23:48:47 -0400983 */
984 public boolean getIsAppImportanceLocked() {
985 return mIsAppImportanceLocked;
986 }
987
Julia Reynolds924eed12017-01-19 09:52:07 -0500988 protected void updateNotificationChannel(NotificationChannel channel) {
989 if (channel != null) {
990 mChannel = channel;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500991 calculateImportance();
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500992 calculateUserSentiment();
Julia Reynolds22f02b32016-12-01 15:05:13 -0500993 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400994 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500995
Julia Reynolds924eed12017-01-19 09:52:07 -0500996 public void setShowBadge(boolean showBadge) {
997 mShowBadge = showBadge;
998 }
999
1000 public boolean canShowBadge() {
1001 return mShowBadge;
1002 }
1003
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05001004 public Light getLight() {
1005 return mLight;
1006 }
1007
Julia Reynolds0c299d42016-11-15 14:37:04 -05001008 public Uri getSound() {
1009 return mSound;
1010 }
1011
1012 public long[] getVibration() {
1013 return mVibration;
1014 }
1015
1016 public AudioAttributes getAudioAttributes() {
1017 return mAttributes;
1018 }
Julia Reynolds22f02b32016-12-01 15:05:13 -05001019
1020 public ArrayList<String> getPeopleOverride() {
1021 return mPeopleOverride;
1022 }
1023
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001024 public void setInterruptive(boolean interruptive) {
1025 mIsInterruptive = interruptive;
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -04001026 final long now = System.currentTimeMillis();
1027 mInterruptionTimeMs = interruptive ? now : mInterruptionTimeMs;
1028
1029 if (interruptive) {
1030 MetricsLogger.action(getLogMaker()
1031 .setCategory(MetricsEvent.NOTIFICATION_INTERRUPTION)
1032 .setType(MetricsEvent.TYPE_OPEN)
1033 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS,
1034 getInterruptionMs(now)));
1035 MetricsLogger.histogram(mContext, "note_interruptive", getInterruptionMs(now));
1036 }
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001037 }
1038
Gus Prevasa3226492018-10-23 11:10:09 -04001039 public void setAudiblyAlerted(boolean audiblyAlerted) {
1040 mAudiblyAlerted = audiblyAlerted;
1041 }
1042
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001043 public void setTextChanged(boolean textChanged) {
1044 mTextChanged = textChanged;
1045 }
1046
1047 public void setRecordedInterruption(boolean recorded) {
1048 mRecordedInterruption = recorded;
1049 }
1050
1051 public boolean hasRecordedInterruption() {
1052 return mRecordedInterruption;
1053 }
1054
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001055 public boolean isInterruptive() {
1056 return mIsInterruptive;
1057 }
1058
Gus Prevasa3226492018-10-23 11:10:09 -04001059 /** Returns true if the notification audibly alerted the user. */
1060 public boolean getAudiblyAlerted() {
1061 return mAudiblyAlerted;
1062 }
1063
Julia Reynolds22f02b32016-12-01 15:05:13 -05001064 protected void setPeopleOverride(ArrayList<String> people) {
1065 mPeopleOverride = people;
1066 }
1067
1068 public ArrayList<SnoozeCriterion> getSnoozeCriteria() {
1069 return mSnoozeCriteria;
1070 }
1071
1072 protected void setSnoozeCriteria(ArrayList<SnoozeCriterion> snoozeCriteria) {
1073 mSnoozeCriteria = snoozeCriteria;
1074 }
Chris Wren9eb5e102017-01-26 13:15:06 -05001075
Julia Reynoldsc65656a2018-02-12 09:55:14 -05001076 private void calculateUserSentiment() {
Rohan Shah590e1b22018-04-10 23:48:47 -04001077 if ((getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0
1078 || mIsAppImportanceLocked) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -05001079 mUserSentiment = USER_SENTIMENT_POSITIVE;
1080 }
1081 }
1082
Julia Reynolds503ed942017-10-04 16:04:56 -04001083 private void setUserSentiment(int userSentiment) {
1084 mUserSentiment = userSentiment;
1085 }
1086
1087 public int getUserSentiment() {
1088 return mUserSentiment;
1089 }
1090
1091 public NotificationStats getStats() {
1092 return mStats;
1093 }
1094
1095 public void recordExpanded() {
1096 mStats.setExpanded();
1097 }
1098
1099 public void recordDirectReplied() {
1100 mStats.setDirectReplied();
1101 }
1102
1103 public void recordDismissalSurface(@NotificationStats.DismissalSurface int surface) {
1104 mStats.setDismissalSurface(surface);
1105 }
1106
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04001107 public void recordDismissalSentiment(@NotificationStats.DismissalSentiment int sentiment) {
1108 mStats.setDismissalSentiment(sentiment);
1109 }
1110
Julia Reynolds503ed942017-10-04 16:04:56 -04001111 public void recordSnoozed() {
1112 mStats.setSnoozed();
1113 }
1114
1115 public void recordViewedSettings() {
1116 mStats.setViewedSettings();
1117 }
1118
Kenny Guy23991102018-04-05 21:18:38 +01001119 public void setNumSmartRepliesAdded(int noReplies) {
1120 mNumberOfSmartRepliesAdded = noReplies;
1121 }
1122
1123 public int getNumSmartRepliesAdded() {
1124 return mNumberOfSmartRepliesAdded;
1125 }
1126
1127 public boolean hasSeenSmartReplies() {
1128 return mHasSeenSmartReplies;
1129 }
1130
1131 public void setSeenSmartReplies(boolean hasSeenSmartReplies) {
1132 mHasSeenSmartReplies = hasSeenSmartReplies;
1133 }
1134
Tony Mak628cb932018-06-19 18:30:41 +01001135 public void setSmartActions(ArrayList<Notification.Action> smartActions) {
1136 mSmartActions = smartActions;
1137 }
1138
1139 public ArrayList<Notification.Action> getSmartActions() {
1140 return mSmartActions;
1141 }
1142
Tony Makc9acf672018-07-20 13:58:24 +02001143 public void setSmartReplies(ArrayList<CharSequence> smartReplies) {
1144 mSmartReplies = smartReplies;
1145 }
1146
1147 public ArrayList<CharSequence> getSmartReplies() {
1148 return mSmartReplies;
1149 }
1150
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001151 /**
1152 * @return all {@link Uri} that should have permission granted to whoever
1153 * will be rendering it. This list has already been vetted to only
1154 * include {@link Uri} that the enqueuing app can grant.
1155 */
1156 public @Nullable ArraySet<Uri> getGrantableUris() {
1157 return mGrantableUris;
1158 }
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001159
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001160 /**
1161 * Collect all {@link Uri} that should have permission granted to whoever
1162 * will be rendering it.
1163 */
Julia Reynolds218871e2018-06-13 10:45:21 -04001164 protected void calculateGrantableUris() {
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001165 final Notification notification = getNotification();
Jeff Sharkey23b31182018-04-18 21:32:12 -06001166 notification.visitUris((uri) -> {
Julia Reynolds218871e2018-06-13 10:45:21 -04001167 visitGrantableUri(uri, false);
Jeff Sharkey23b31182018-04-18 21:32:12 -06001168 });
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001169
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001170 if (notification.getChannelId() != null) {
1171 NotificationChannel channel = getChannel();
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001172 if (channel != null) {
Julia Reynolds218871e2018-06-13 10:45:21 -04001173 visitGrantableUri(channel.getSound(), (channel.getUserLockedFields()
1174 & NotificationChannel.USER_LOCKED_SOUND) != 0);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001175 }
1176 }
1177 }
1178
1179 /**
1180 * Note the presence of a {@link Uri} that should have permission granted to
1181 * whoever will be rendering it.
1182 * <p>
1183 * If the enqueuing app has the ability to grant access, it will be added to
1184 * {@link #mGrantableUris}. Otherwise, this will either log or throw
1185 * {@link SecurityException} depending on target SDK of enqueuing app.
1186 */
Julia Reynolds218871e2018-06-13 10:45:21 -04001187 private void visitGrantableUri(Uri uri, boolean userOverriddenUri) {
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001188 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
1189
1190 // We can't grant Uri permissions from system
1191 final int sourceUid = sbn.getUid();
1192 if (sourceUid == android.os.Process.SYSTEM_UID) return;
1193
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001194 final long ident = Binder.clearCallingIdentity();
1195 try {
1196 // This will throw SecurityException if caller can't grant
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001197 mUgmInternal.checkGrantUriPermission(sourceUid, null,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001198 ContentProvider.getUriWithoutUserId(uri),
1199 Intent.FLAG_GRANT_READ_URI_PERMISSION,
1200 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
1201
1202 if (mGrantableUris == null) {
1203 mGrantableUris = new ArraySet<>();
1204 }
1205 mGrantableUris.add(uri);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001206 } catch (SecurityException e) {
Julia Reynolds218871e2018-06-13 10:45:21 -04001207 if (!userOverriddenUri) {
1208 if (mTargetSdkVersion >= Build.VERSION_CODES.P) {
1209 throw e;
1210 } else {
1211 Log.w(TAG, "Ignoring " + uri + " from " + sourceUid + ": " + e.getMessage());
1212 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06001213 }
1214 } finally {
1215 Binder.restoreCallingIdentity(ident);
1216 }
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001217 }
1218
Chris Wren9eb5e102017-01-26 13:15:06 -05001219 public LogMaker getLogMaker(long now) {
1220 if (mLogMaker == null) {
Chris Wrenb3921792017-06-01 13:34:46 -04001221 // initialize fields that only change on update (so a new record)
Chris Wren9eb5e102017-01-26 13:15:06 -05001222 mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
1223 .setPackageName(sbn.getPackageName())
1224 .addTaggedData(MetricsEvent.NOTIFICATION_ID, sbn.getId())
Chris Wrenb3921792017-06-01 13:34:46 -04001225 .addTaggedData(MetricsEvent.NOTIFICATION_TAG, sbn.getTag())
1226 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag());
Chris Wren9eb5e102017-01-26 13:15:06 -05001227 }
Chris Wrenb3921792017-06-01 13:34:46 -04001228 // reset fields that can change between updates, or are used by multiple logs
Chris Wren9eb5e102017-01-26 13:15:06 -05001229 return mLogMaker
Chris Wrena7c1b802017-03-07 10:17:20 -05001230 .clearCategory()
1231 .clearType()
1232 .clearSubtype()
Chris Wren9eb5e102017-01-26 13:15:06 -05001233 .clearTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX)
Chris Wrenb3921792017-06-01 13:34:46 -04001234 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance)
1235 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
1236 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
1237 sbn.getNotification().isGroupSummary() ? 1 : 0)
Chris Wren9eb5e102017-01-26 13:15:06 -05001238 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now))
1239 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now))
Julia Reynoldsd6ba35c2018-06-18 09:29:19 -04001240 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now))
1241 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS,
1242 getInterruptionMs(now));
Chris Wren9eb5e102017-01-26 13:15:06 -05001243 }
1244
1245 public LogMaker getLogMaker() {
1246 return getLogMaker(System.currentTimeMillis());
1247 }
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05001248
Julia Reynolds3dfdde02018-10-08 09:17:56 -04001249 public LogMaker getItemLogMaker() {
1250 return getLogMaker().setCategory(MetricsEvent.NOTIFICATION_ITEM);
1251 }
1252
1253 public LogMaker getAdjustmentLogMaker() {
1254 return getLogMaker()
1255 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
1256 .setType(MetricsEvent.NOTIFICATION_ASSISTANT_ADJUSTMENT);
1257 }
1258
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05001259 @VisibleForTesting
1260 static final class Light {
1261 public final int color;
1262 public final int onMs;
1263 public final int offMs;
1264
1265 public Light(int color, int onMs, int offMs) {
1266 this.color = color;
1267 this.onMs = onMs;
1268 this.offMs = offMs;
1269 }
1270
1271 @Override
1272 public boolean equals(Object o) {
1273 if (this == o) return true;
1274 if (o == null || getClass() != o.getClass()) return false;
1275
1276 Light light = (Light) o;
1277
1278 if (color != light.color) return false;
1279 if (onMs != light.onMs) return false;
1280 return offMs == light.offMs;
1281
1282 }
1283
1284 @Override
1285 public int hashCode() {
1286 int result = color;
1287 result = 31 * result + onMs;
1288 result = 31 * result + offMs;
1289 return result;
1290 }
1291
1292 @Override
1293 public String toString() {
1294 return "Light{" +
1295 "color=" + color +
1296 ", onMs=" + onMs +
1297 ", offMs=" + offMs +
1298 '}';
1299 }
1300 }
Chris Wren333a61c2014-05-28 16:40:57 -04001301}