blob: 6c5685df503d68c84246cd6df7e15e6789dd2f47 [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
Chris Wren47633422016-01-22 09:56:59 -050018import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
Chris Wrenbdf33762015-12-04 15:50:51 -050019import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
20import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
21import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_LOW;
22import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
23
Chris Wren333a61c2014-05-28 16:40:57 -040024import android.app.Notification;
25import android.content.Context;
Julia Reynolds83fa1072016-02-17 09:10:19 -050026import android.content.pm.ApplicationInfo;
Chris Wren333a61c2014-05-28 16:40:57 -040027import android.content.pm.PackageManager.NameNotFoundException;
28import android.content.res.Resources;
29import android.graphics.Bitmap;
Dan Sandlerd63f9322015-05-06 15:18:49 -040030import android.graphics.drawable.Icon;
John Spurlockbfa5dc42014-07-28 23:30:45 -040031import android.media.AudioAttributes;
Julia Reynolds83fa1072016-02-17 09:10:19 -050032import android.os.Build;
Chris Wrenda4bd202014-09-04 15:53:52 -040033import android.os.UserHandle;
Julia Reynolds5d25ee72015-11-20 15:38:20 -050034import android.service.notification.NotificationListenerService;
Chris Wren333a61c2014-05-28 16:40:57 -040035import android.service.notification.StatusBarNotification;
John Spurlockbfa5dc42014-07-28 23:30:45 -040036
Chris Wren1031c972014-07-23 13:11:45 +000037import com.android.internal.annotations.VisibleForTesting;
Chris Wren6650e572015-05-15 17:19:25 -040038import com.android.server.EventLogTags;
Chris Wren333a61c2014-05-28 16:40:57 -040039
40import java.io.PrintWriter;
41import java.lang.reflect.Array;
42import java.util.Arrays;
John Spurlock312d1d02014-07-08 10:24:57 -040043import java.util.Objects;
Chris Wren333a61c2014-05-28 16:40:57 -040044
45/**
46 * Holds data about notifications that should not be shared with the
47 * {@link android.service.notification.NotificationListenerService}s.
48 *
49 * <p>These objects should not be mutated unless the code is synchronized
50 * on {@link NotificationManagerService#mNotificationList}, and any
51 * modification should be followed by a sorting of that list.</p>
52 *
53 * <p>Is sortable by {@link NotificationComparator}.</p>
54 *
55 * {@hide}
56 */
57public final class NotificationRecord {
58 final StatusBarNotification sbn;
Christoph Studer365e4c32014-09-18 20:35:36 +020059 final int mOriginalFlags;
Chris Wrenbdf33762015-12-04 15:50:51 -050060 private final Context mContext;
Christoph Studer365e4c32014-09-18 20:35:36 +020061
Chris Wren333a61c2014-05-28 16:40:57 -040062 NotificationUsageStats.SingleNotificationStats stats;
63 boolean isCanceled;
Amith Yamasanif47e51e2015-04-17 10:02:15 -070064 /** Whether the notification was seen by the user via one of the notification listeners. */
65 boolean mIsSeen;
Chris Wren333a61c2014-05-28 16:40:57 -040066
67 // These members are used by NotificationSignalExtractors
68 // to communicate with the ranking module.
69 private float mContactAffinity;
70 private boolean mRecentlyIntrusive;
71
72 // is this notification currently being intercepted by Zen Mode?
73 private boolean mIntercept;
Chris Wren333a61c2014-05-28 16:40:57 -040074
Christoph Studer52b7a5a2014-06-06 16:09:15 +020075 // The timestamp used for ranking.
76 private long mRankingTimeMs;
77
Chris Wren640e3872015-04-21 13:23:18 -040078 // The first post time, stable across updates.
79 private long mCreationTimeMs;
80
Chris Wren6650e572015-05-15 17:19:25 -040081 // The most recent visibility event.
82 private long mVisibleSinceMs;
83
84 // The most recent update time, or the creation time if no updates.
85 private long mUpdateTimeMs;
86
Chris Wrena3446562014-06-03 18:11:47 -040087 // Is this record an update of an old record?
88 public boolean isUpdate;
Chris Wren54bbef42014-07-09 18:37:56 -040089 private int mPackagePriority;
Chris Wrena3446562014-06-03 18:11:47 -040090
Chris Wren1031c972014-07-23 13:11:45 +000091 private int mAuthoritativeRank;
Christoph Studercd4adf82014-08-19 17:50:49 +020092 private String mGlobalSortKey;
Chris Wren3ad4e3a2014-09-02 17:23:51 -040093 private int mPackageVisibility;
Julia Reynoldsef37f282016-02-12 09:11:27 -050094 private int mUserImportance = IMPORTANCE_UNSPECIFIED;
Chris Wren47633422016-01-22 09:56:59 -050095 private int mImportance = IMPORTANCE_UNSPECIFIED;
Chris Wrenbdf33762015-12-04 15:50:51 -050096 private CharSequence mImportanceExplanation = null;
Chris Wren1031c972014-07-23 13:11:45 +000097
Julia Reynoldsf612869ae2015-11-05 16:48:55 -050098 private int mSuppressedVisualEffects = 0;
Julia Reynoldsef37f282016-02-12 09:11:27 -050099 private String mUserExplanation;
Chris Wrenbdf33762015-12-04 15:50:51 -0500100 private String mPeopleExplanation;
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500101
Chris Wren1031c972014-07-23 13:11:45 +0000102 @VisibleForTesting
Chris Wrenbdf33762015-12-04 15:50:51 -0500103 public NotificationRecord(Context context, StatusBarNotification sbn)
Chris Wren333a61c2014-05-28 16:40:57 -0400104 {
105 this.sbn = sbn;
Christoph Studer365e4c32014-09-18 20:35:36 +0200106 mOriginalFlags = sbn.getNotification().flags;
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200107 mRankingTimeMs = calculateRankingTimeMs(0L);
Chris Wren640e3872015-04-21 13:23:18 -0400108 mCreationTimeMs = sbn.getPostTime();
Chris Wren6650e572015-05-15 17:19:25 -0400109 mUpdateTimeMs = mCreationTimeMs;
Chris Wrenbdf33762015-12-04 15:50:51 -0500110 mContext = context;
Chris Wrencdee8cd2016-01-25 17:10:30 -0500111 stats = new NotificationUsageStats.SingleNotificationStats();
Chris Wrenbdf33762015-12-04 15:50:51 -0500112 mImportance = defaultImportance();
113 }
114
115 private int defaultImportance() {
116 final Notification n = sbn.getNotification();
117 int importance = IMPORTANCE_DEFAULT;
118
119 // Migrate notification flags to scores
120 if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) {
121 n.priority = Notification.PRIORITY_MAX;
122 }
123
124 switch (n.priority) {
125 case Notification.PRIORITY_MIN:
126 case Notification.PRIORITY_LOW:
127 importance = IMPORTANCE_LOW;
128 break;
129 case Notification.PRIORITY_DEFAULT:
130 importance = IMPORTANCE_DEFAULT;
131 break;
132 case Notification.PRIORITY_HIGH:
133 importance = IMPORTANCE_HIGH;
134 break;
135 case Notification.PRIORITY_MAX:
136 importance = IMPORTANCE_MAX;
137 break;
138 }
Chris Wrencdee8cd2016-01-25 17:10:30 -0500139 stats.requestedImportance = importance;
Chris Wrenbdf33762015-12-04 15:50:51 -0500140
141 boolean isNoisy = (n.defaults & Notification.DEFAULT_SOUND) != 0
142 || (n.defaults & Notification.DEFAULT_VIBRATE) != 0
143 || n.sound != null
144 || n.vibrate != null;
Chris Wrencdee8cd2016-01-25 17:10:30 -0500145 stats.isNoisy = isNoisy;
Chris Wrenbdf33762015-12-04 15:50:51 -0500146 if (!isNoisy && importance > IMPORTANCE_DEFAULT) {
147 importance = IMPORTANCE_DEFAULT;
148 }
Chris Wrenbdf33762015-12-04 15:50:51 -0500149
Julia Reynolds83fa1072016-02-17 09:10:19 -0500150 try {
Julia Reynoldsf5df5532016-02-18 08:31:35 -0500151 final ApplicationInfo applicationInfo =
152 mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(),
153 0, sbn.getUser().getIdentifier());
Julia Reynolds83fa1072016-02-17 09:10:19 -0500154 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.N) {
155 if (isNoisy) {
156 if (importance >= IMPORTANCE_HIGH) {
157 importance = IMPORTANCE_MAX;
158 } else {
159 importance = IMPORTANCE_HIGH;
160 }
161 }
162 }
163 } catch (NameNotFoundException e) {
164 // oh well.
165 }
166
Chris Wrenbdf33762015-12-04 15:50:51 -0500167 if (n.fullScreenIntent != null) {
168 importance = IMPORTANCE_MAX;
169 }
170
Chris Wrencdee8cd2016-01-25 17:10:30 -0500171 stats.naturalImportance = importance;
Chris Wrenbdf33762015-12-04 15:50:51 -0500172 return importance;
Chris Wren333a61c2014-05-28 16:40:57 -0400173 }
174
175 // copy any notes that the ranking system may have made before the update
176 public void copyRankingInformation(NotificationRecord previous) {
177 mContactAffinity = previous.mContactAffinity;
178 mRecentlyIntrusive = previous.mRecentlyIntrusive;
Chris Wren54bbef42014-07-09 18:37:56 -0400179 mPackagePriority = previous.mPackagePriority;
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400180 mPackageVisibility = previous.mPackageVisibility;
Chris Wren333a61c2014-05-28 16:40:57 -0400181 mIntercept = previous.mIntercept;
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200182 mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
Chris Wren640e3872015-04-21 13:23:18 -0400183 mCreationTimeMs = previous.mCreationTimeMs;
Chris Wren6650e572015-05-15 17:19:25 -0400184 mVisibleSinceMs = previous.mVisibleSinceMs;
Julia Reynoldsef37f282016-02-12 09:11:27 -0500185 mUserImportance = previous.mUserImportance;
Chris Wrenbdf33762015-12-04 15:50:51 -0500186 mImportance = previous.mImportance;
187 mImportanceExplanation = previous.mImportanceExplanation;
Christoph Studercd4adf82014-08-19 17:50:49 +0200188 // Don't copy mGlobalSortKey, recompute it.
Chris Wren333a61c2014-05-28 16:40:57 -0400189 }
190
191 public Notification getNotification() { return sbn.getNotification(); }
192 public int getFlags() { return sbn.getNotification().flags; }
Chris Wrenda4bd202014-09-04 15:53:52 -0400193 public UserHandle getUser() { return sbn.getUser(); }
Chris Wren333a61c2014-05-28 16:40:57 -0400194 public String getKey() { return sbn.getKey(); }
Chris Wrenda4bd202014-09-04 15:53:52 -0400195 /** @deprecated Use {@link #getUser()} instead. */
196 public int getUserId() { return sbn.getUserId(); }
Chris Wren333a61c2014-05-28 16:40:57 -0400197
Dan Sandlera1770312015-07-10 13:59:29 -0400198 void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
Chris Wren333a61c2014-05-28 16:40:57 -0400199 final Notification notification = sbn.getNotification();
Dan Sandlerd63f9322015-05-06 15:18:49 -0400200 final Icon icon = notification.getSmallIcon();
201 String iconStr = String.valueOf(icon);
202 if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
203 iconStr += " / " + idDebugString(baseContext, icon.getResPackage(), icon.getResId());
204 }
Chris Wren333a61c2014-05-28 16:40:57 -0400205 pw.println(prefix + this);
206 pw.println(prefix + " uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
Dan Sandlerd63f9322015-05-06 15:18:49 -0400207 pw.println(prefix + " icon=" + iconStr);
Chris Wrenbdf33762015-12-04 15:50:51 -0500208 pw.println(prefix + " pri=" + notification.priority);
Chris Wren333a61c2014-05-28 16:40:57 -0400209 pw.println(prefix + " key=" + sbn.getKey());
Amith Yamasani24bd0be2015-04-28 10:28:09 -0700210 pw.println(prefix + " seen=" + mIsSeen);
Chris Wren1031c972014-07-23 13:11:45 +0000211 pw.println(prefix + " groupKey=" + getGroupKey());
Chris Wren333a61c2014-05-28 16:40:57 -0400212 pw.println(prefix + " contentIntent=" + notification.contentIntent);
213 pw.println(prefix + " deleteIntent=" + notification.deleteIntent);
214 pw.println(prefix + " tickerText=" + notification.tickerText);
215 pw.println(prefix + " contentView=" + notification.contentView);
216 pw.println(prefix + String.format(" defaults=0x%08x flags=0x%08x",
217 notification.defaults, notification.flags));
218 pw.println(prefix + " sound=" + notification.sound);
John Spurlockbfa5dc42014-07-28 23:30:45 -0400219 pw.println(prefix + " audioStreamType=" + notification.audioStreamType);
220 pw.println(prefix + " audioAttributes=" + notification.audioAttributes);
Chris Wren333a61c2014-05-28 16:40:57 -0400221 pw.println(prefix + String.format(" color=0x%08x", notification.color));
222 pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
223 pw.println(prefix + String.format(" led=0x%08x onMs=%d offMs=%d",
224 notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
225 if (notification.actions != null && notification.actions.length > 0) {
226 pw.println(prefix + " actions={");
227 final int N = notification.actions.length;
228 for (int i=0; i<N; i++) {
229 final Notification.Action action = notification.actions[i];
Chris Wren1ac52a92016-02-24 14:54:52 -0500230 if (action != null) {
231 pw.println(String.format("%s [%d] \"%s\" -> %s",
232 prefix,
233 i,
234 action.title,
235 action.actionIntent == null ? "null" : action.actionIntent.toString()
236 ));
237 }
Chris Wren333a61c2014-05-28 16:40:57 -0400238 }
239 pw.println(prefix + " }");
240 }
241 if (notification.extras != null && notification.extras.size() > 0) {
242 pw.println(prefix + " extras={");
243 for (String key : notification.extras.keySet()) {
244 pw.print(prefix + " " + key + "=");
245 Object val = notification.extras.get(key);
246 if (val == null) {
247 pw.println("null");
248 } else {
249 pw.print(val.getClass().getSimpleName());
Dan Sandlera1770312015-07-10 13:59:29 -0400250 if (redact && (val instanceof CharSequence || val instanceof String)) {
Chris Wren333a61c2014-05-28 16:40:57 -0400251 // redact contents from bugreports
252 } else if (val instanceof Bitmap) {
253 pw.print(String.format(" (%dx%d)",
254 ((Bitmap) val).getWidth(),
255 ((Bitmap) val).getHeight()));
256 } else if (val.getClass().isArray()) {
257 final int N = Array.getLength(val);
Dan Sandlera1770312015-07-10 13:59:29 -0400258 pw.print(" (" + N + ")");
259 if (!redact) {
260 for (int j=0; j<N; j++) {
261 pw.println();
262 pw.print(String.format("%s [%d] %s",
263 prefix, j, String.valueOf(Array.get(val, j))));
264 }
265 }
Chris Wren333a61c2014-05-28 16:40:57 -0400266 } else {
267 pw.print(" (" + String.valueOf(val) + ")");
268 }
269 pw.println();
270 }
271 }
272 pw.println(prefix + " }");
273 }
274 pw.println(prefix + " stats=" + stats.toString());
275 pw.println(prefix + " mContactAffinity=" + mContactAffinity);
276 pw.println(prefix + " mRecentlyIntrusive=" + mRecentlyIntrusive);
Chris Wren54bbef42014-07-09 18:37:56 -0400277 pw.println(prefix + " mPackagePriority=" + mPackagePriority);
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400278 pw.println(prefix + " mPackageVisibility=" + mPackageVisibility);
Julia Reynoldsef37f282016-02-12 09:11:27 -0500279 pw.println(prefix + " mUserImportance="
280 + NotificationListenerService.Ranking.importanceToString(mUserImportance));
Chris Wrenbdf33762015-12-04 15:50:51 -0500281 pw.println(prefix + " mImportance="
282 + NotificationListenerService.Ranking.importanceToString(mImportance));
283 pw.println(prefix + " mImportanceExplanation=" + mImportanceExplanation);
Chris Wren333a61c2014-05-28 16:40:57 -0400284 pw.println(prefix + " mIntercept=" + mIntercept);
Christoph Studercd4adf82014-08-19 17:50:49 +0200285 pw.println(prefix + " mGlobalSortKey=" + mGlobalSortKey);
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200286 pw.println(prefix + " mRankingTimeMs=" + mRankingTimeMs);
Chris Wren640e3872015-04-21 13:23:18 -0400287 pw.println(prefix + " mCreationTimeMs=" + mCreationTimeMs);
Chris Wren6650e572015-05-15 17:19:25 -0400288 pw.println(prefix + " mVisibleSinceMs=" + mVisibleSinceMs);
289 pw.println(prefix + " mUpdateTimeMs=" + mUpdateTimeMs);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500290 pw.println(prefix + " mSuppressedVisualEffects= " + mSuppressedVisualEffects);
Chris Wren333a61c2014-05-28 16:40:57 -0400291 }
292
293
294 static String idDebugString(Context baseContext, String packageName, int id) {
295 Context c;
296
297 if (packageName != null) {
298 try {
299 c = baseContext.createPackageContext(packageName, 0);
300 } catch (NameNotFoundException e) {
301 c = baseContext;
302 }
303 } else {
304 c = baseContext;
305 }
306
307 Resources r = c.getResources();
308 try {
309 return r.getResourceName(id);
310 } catch (Resources.NotFoundException e) {
311 return "<name unknown>";
312 }
313 }
314
315 @Override
316 public final String toString() {
317 return String.format(
Chris Wrenbdf33762015-12-04 15:50:51 -0500318 "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s importance=%d key=%s: %s)",
Chris Wren333a61c2014-05-28 16:40:57 -0400319 System.identityHashCode(this),
320 this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(),
Chris Wrenbdf33762015-12-04 15:50:51 -0500321 this.sbn.getTag(), this.mImportance, this.sbn.getKey(),
Chris Wren333a61c2014-05-28 16:40:57 -0400322 this.sbn.getNotification());
323 }
324
325 public void setContactAffinity(float contactAffinity) {
326 mContactAffinity = contactAffinity;
Chris Wrenbdf33762015-12-04 15:50:51 -0500327 if (mImportance < IMPORTANCE_DEFAULT &&
328 mContactAffinity > ValidateNotificationPeople.VALID_CONTACT) {
329 setImportance(IMPORTANCE_DEFAULT, getPeopleExplanation());
330 }
Chris Wren333a61c2014-05-28 16:40:57 -0400331 }
332
333 public float getContactAffinity() {
334 return mContactAffinity;
335 }
336
John Spurlock1d881a12015-03-18 19:21:54 -0400337 public void setRecentlyIntrusive(boolean recentlyIntrusive) {
Chris Wren333a61c2014-05-28 16:40:57 -0400338 mRecentlyIntrusive = recentlyIntrusive;
339 }
340
341 public boolean isRecentlyIntrusive() {
342 return mRecentlyIntrusive;
343 }
344
Chris Wren54bbef42014-07-09 18:37:56 -0400345 public void setPackagePriority(int packagePriority) {
John Spurlock6ac5f8d2014-07-18 11:27:54 -0400346 mPackagePriority = packagePriority;
Chris Wren54bbef42014-07-09 18:37:56 -0400347 }
348
349 public int getPackagePriority() {
350 return mPackagePriority;
351 }
352
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400353 public void setPackageVisibilityOverride(int packageVisibility) {
354 mPackageVisibility = packageVisibility;
355 }
356
357 public int getPackageVisibilityOverride() {
358 return mPackageVisibility;
359 }
360
Julia Reynoldsef37f282016-02-12 09:11:27 -0500361 public void setUserImportance(int importance) {
362 mUserImportance = importance;
363 applyUserImportance();
Chris Wrenbdf33762015-12-04 15:50:51 -0500364 }
365
Julia Reynoldsef37f282016-02-12 09:11:27 -0500366 private String getUserExplanation() {
367 if (mUserExplanation == null) {
368 mUserExplanation =
369 mContext.getString(com.android.internal.R.string.importance_from_user);
Chris Wrenbdf33762015-12-04 15:50:51 -0500370 }
Julia Reynoldsef37f282016-02-12 09:11:27 -0500371 return mUserExplanation;
Chris Wrenbdf33762015-12-04 15:50:51 -0500372 }
373
374 private String getPeopleExplanation() {
375 if (mPeopleExplanation == null) {
376 mPeopleExplanation =
377 mContext.getString(com.android.internal.R.string.importance_from_person);
378 }
379 return mPeopleExplanation;
380 }
381
Julia Reynoldsef37f282016-02-12 09:11:27 -0500382 private void applyUserImportance() {
383 if (mUserImportance != NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED) {
384 mImportance = mUserImportance;
385 mImportanceExplanation = getUserExplanation();
Julia Reynolds5d25ee72015-11-20 15:38:20 -0500386 }
387 }
388
Julia Reynoldsef37f282016-02-12 09:11:27 -0500389 public int getUserImportance() {
390 return mUserImportance;
Julia Reynolds5d25ee72015-11-20 15:38:20 -0500391 }
392
Chris Wrenbdf33762015-12-04 15:50:51 -0500393 public void setImportance(int importance, CharSequence explanation) {
394 if (importance != NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED) {
395 mImportance = importance;
396 mImportanceExplanation = explanation;
397 }
Julia Reynoldsef37f282016-02-12 09:11:27 -0500398 applyUserImportance();
Chris Wrenbdf33762015-12-04 15:50:51 -0500399 }
400
401 public int getImportance() {
402 return mImportance;
403 }
404
405 public CharSequence getImportanceExplanation() {
406 return mImportanceExplanation;
407 }
408
Chris Wren333a61c2014-05-28 16:40:57 -0400409 public boolean setIntercepted(boolean intercept) {
410 mIntercept = intercept;
411 return mIntercept;
412 }
413
414 public boolean isIntercepted() {
415 return mIntercept;
416 }
417
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500418 public void setSuppressedVisualEffects(int effects) {
419 mSuppressedVisualEffects = effects;
420 }
421
422 public int getSuppressedVisualEffects() {
423 return mSuppressedVisualEffects;
424 }
425
John Spurlock312d1d02014-07-08 10:24:57 -0400426 public boolean isCategory(String category) {
John Spurlockbfa5dc42014-07-28 23:30:45 -0400427 return Objects.equals(getNotification().category, category);
428 }
429
430 public boolean isAudioStream(int stream) {
431 return getNotification().audioStreamType == stream;
432 }
433
434 public boolean isAudioAttributesUsage(int usage) {
435 final AudioAttributes attributes = getNotification().audioAttributes;
436 return attributes != null && attributes.getUsage() == usage;
John Spurlock312d1d02014-07-08 10:24:57 -0400437 }
438
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200439 /**
440 * Returns the timestamp to use for time-based sorting in the ranker.
441 */
442 public long getRankingTimeMs() {
443 return mRankingTimeMs;
444 }
445
446 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400447 * @param now this current time in milliseconds.
448 * @returns the number of milliseconds since the most recent update, or the post time if none.
Chris Wren6650e572015-05-15 17:19:25 -0400449 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400450 public int getFreshnessMs(long now) {
451 return (int) (now - mUpdateTimeMs);
Chris Wren6650e572015-05-15 17:19:25 -0400452 }
453
454 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400455 * @param now this current time in milliseconds.
456 * @returns the number of milliseconds since the the first post, ignoring updates.
Chris Wren640e3872015-04-21 13:23:18 -0400457 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400458 public int getLifespanMs(long now) {
459 return (int) (now - mCreationTimeMs);
Chris Wren640e3872015-04-21 13:23:18 -0400460 }
461
462 /**
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400463 * @param now this current time in milliseconds.
464 * @returns the number of milliseconds since the most recent visibility event, or 0 if never.
Chris Wren6650e572015-05-15 17:19:25 -0400465 */
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400466 public int getExposureMs(long now) {
467 return mVisibleSinceMs == 0 ? 0 : (int) (now - mVisibleSinceMs);
Chris Wren6650e572015-05-15 17:19:25 -0400468 }
469
470 /**
471 * Set the visibility of the notification.
472 */
Chris Wrend1dbc922015-06-19 17:51:16 -0400473 public void setVisibility(boolean visible, int rank) {
Chris Wren6650e572015-05-15 17:19:25 -0400474 final long now = System.currentTimeMillis();
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400475 mVisibleSinceMs = visible ? now : mVisibleSinceMs;
Chris Wren6650e572015-05-15 17:19:25 -0400476 stats.onVisibilityChanged(visible);
477 EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0,
478 (int) (now - mCreationTimeMs),
Chris Wrend1dbc922015-06-19 17:51:16 -0400479 (int) (now - mUpdateTimeMs),
480 0, // exposure time
481 rank);
Chris Wren6650e572015-05-15 17:19:25 -0400482 }
483
484 /**
Christoph Studer52b7a5a2014-06-06 16:09:15 +0200485 * @param previousRankingTimeMs for updated notifications, {@link #getRankingTimeMs()}
486 * of the previous notification record, 0 otherwise
487 */
488 private long calculateRankingTimeMs(long previousRankingTimeMs) {
489 Notification n = getNotification();
490 // Take developer provided 'when', unless it's in the future.
491 if (n.when != 0 && n.when <= sbn.getPostTime()) {
492 return n.when;
493 }
494 // If we've ranked a previous instance with a timestamp, inherit it. This case is
495 // important in order to have ranking stability for updating notifications.
496 if (previousRankingTimeMs > 0) {
497 return previousRankingTimeMs;
498 }
499 return sbn.getPostTime();
500 }
Chris Wren1031c972014-07-23 13:11:45 +0000501
Christoph Studercd4adf82014-08-19 17:50:49 +0200502 public void setGlobalSortKey(String globalSortKey) {
503 mGlobalSortKey = globalSortKey;
Chris Wren1031c972014-07-23 13:11:45 +0000504 }
505
Christoph Studercd4adf82014-08-19 17:50:49 +0200506 public String getGlobalSortKey() {
507 return mGlobalSortKey;
Chris Wren1031c972014-07-23 13:11:45 +0000508 }
509
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700510 /** Check if any of the listeners have marked this notification as seen by the user. */
511 public boolean isSeen() {
512 return mIsSeen;
513 }
514
515 /** Mark the notification as seen by the user. */
516 public void setSeen() {
517 mIsSeen = true;
518 }
519
Chris Wren1031c972014-07-23 13:11:45 +0000520 public void setAuthoritativeRank(int authoritativeRank) {
521 mAuthoritativeRank = authoritativeRank;
522 }
523
524 public int getAuthoritativeRank() {
525 return mAuthoritativeRank;
526 }
527
528 public String getGroupKey() {
529 return sbn.getGroupKey();
530 }
Chris Wren47633422016-01-22 09:56:59 -0500531
532 public boolean isImportanceFromUser() {
Julia Reynoldsef37f282016-02-12 09:11:27 -0500533 return mImportance == mUserImportance;
Chris Wren47633422016-01-22 09:56:59 -0500534 }
Chris Wren333a61c2014-05-28 16:40:57 -0400535}