blob: 954dc39430193c6d585fdd3112929d5687fee15b [file] [log] [blame]
Joe Onorato18e69df2010-05-17 22:26:12 -07001/*
2 * Copyright (C) 2008 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 */
16
Daniel Sandler5feceeb2013-03-22 18:29:23 -070017package android.service.notification;
Joe Onorato18e69df2010-05-17 22:26:12 -070018
Mathew Inwoode3807372018-08-10 09:51:03 +010019import android.annotation.UnsupportedAppUsage;
Joe Onorato18e69df2010-05-17 22:26:12 -070020import android.app.Notification;
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -040021import android.app.NotificationManager;
Dan Sandler68079d52015-07-22 10:45:30 -040022import android.content.Context;
23import android.content.pm.ApplicationInfo;
24import android.content.pm.PackageManager;
Eyal Posenera9cf9c72018-12-18 16:23:54 +020025import android.metrics.LogMaker;
Mathew Inwood31755f92018-12-20 13:53:36 +000026import android.os.Build;
Joe Onorato18e69df2010-05-17 22:26:12 -070027import android.os.Parcel;
28import android.os.Parcelable;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070029import android.os.UserHandle;
Joe Onorato18e69df2010-05-17 22:26:12 -070030
Will Brockman828427e2019-01-28 09:55:45 -050031import com.android.internal.logging.nano.MetricsProto;
Eyal Posenera9cf9c72018-12-18 16:23:54 +020032import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
33
Daniel Sandler2561b0b2012-02-13 21:04:12 -050034/**
Daniel Sandlerfde19b12013-01-17 00:21:05 -050035 * Class encapsulating a Notification. Sent by the NotificationManagerService to clients including
Daniel Sandler5feceeb2013-03-22 18:29:23 -070036 * the status bar and any {@link android.service.notification.NotificationListenerService}s.
Daniel Sandler2561b0b2012-02-13 21:04:12 -050037 */
Joe Onorato18e69df2010-05-17 22:26:12 -070038public class StatusBarNotification implements Parcelable {
Eyal Posenera9cf9c72018-12-18 16:23:54 +020039 static final int MAX_LOG_TAG_LENGTH = 36;
40
Mathew Inwoode3807372018-08-10 09:51:03 +010041 @UnsupportedAppUsage
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040042 private final String pkg;
Mathew Inwoode3807372018-08-10 09:51:03 +010043 @UnsupportedAppUsage
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040044 private final int id;
Mathew Inwood31755f92018-12-20 13:53:36 +000045 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040046 private final String tag;
John Spurlocka4294292014-03-24 18:02:32 -040047 private final String key;
Julia Reynoldse46bb372016-03-17 11:05:58 -040048 private String groupKey;
49 private String overrideGroupKey;
Daniel Sandler5feceeb2013-03-22 18:29:23 -070050
Mathew Inwoode3807372018-08-10 09:51:03 +010051 @UnsupportedAppUsage
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040052 private final int uid;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -040053 private final String opPkg;
Mathew Inwood31755f92018-12-20 13:53:36 +000054 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040055 private final int initialPid;
Mathew Inwood31755f92018-12-20 13:53:36 +000056 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040057 private final Notification notification;
Mathew Inwood31755f92018-12-20 13:53:36 +000058 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040059 private final UserHandle user;
Mathew Inwood31755f92018-12-20 13:53:36 +000060 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040061 private final long postTime;
Jeff Sharkey6d515712012-09-20 16:06:08 -070062
Dan Sandler68079d52015-07-22 10:45:30 -040063 private Context mContext; // used for inflation & icon expansion
Daniel Sandler5feceeb2013-03-22 18:29:23 -070064
Eyal Posenera9cf9c72018-12-18 16:23:54 +020065 // Contains the basic logging data of the notification.
66 private LogMaker mLogMaker;
67
Daniel Sandler5feceeb2013-03-22 18:29:23 -070068 /** @hide */
Julia Reynolds924eed12017-01-19 09:52:07 -050069 public StatusBarNotification(String pkg, String opPkg, int id,
Julia Reynolds423b9fc2016-11-09 09:51:08 -050070 String tag, int uid, int initialPid, Notification notification, UserHandle user,
71 String overrideGroupKey, long postTime) {
Julia Reynoldse46bb372016-03-17 11:05:58 -040072 if (pkg == null) throw new NullPointerException();
73 if (notification == null) throw new NullPointerException();
74
75 this.pkg = pkg;
76 this.opPkg = opPkg;
77 this.id = id;
78 this.tag = tag;
79 this.uid = uid;
80 this.initialPid = initialPid;
81 this.notification = notification;
82 this.user = user;
83 this.postTime = postTime;
84 this.overrideGroupKey = overrideGroupKey;
85 this.key = key();
86 this.groupKey = groupKey();
87 }
88
Julia Reynoldsa11d0b12017-02-16 15:01:36 -050089 /**
90 * @deprecated Non-system apps should not need to create StatusBarNotifications.
91 */
Julia Reynolds423b9fc2016-11-09 09:51:08 -050092 @Deprecated
Christoph Studer8fd7f1e2014-04-11 17:35:05 -040093 public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
Daniel Sandlerfde19b12013-01-17 00:21:05 -050094 int initialPid, int score, Notification notification, UserHandle user,
95 long postTime) {
Joe Onorato18e69df2010-05-17 22:26:12 -070096 if (pkg == null) throw new NullPointerException();
97 if (notification == null) throw new NullPointerException();
98
99 this.pkg = pkg;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400100 this.opPkg = opPkg;
Joe Onorato18e69df2010-05-17 22:26:12 -0700101 this.id = id;
102 this.tag = tag;
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700103 this.uid = uid;
104 this.initialPid = initialPid;
Joe Onorato18e69df2010-05-17 22:26:12 -0700105 this.notification = notification;
Jeff Sharkey6d515712012-09-20 16:06:08 -0700106 this.user = user;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500107 this.postTime = postTime;
John Spurlocka4294292014-03-24 18:02:32 -0400108 this.key = key();
Chris Wren1031c972014-07-23 13:11:45 +0000109 this.groupKey = groupKey();
Joe Onorato18e69df2010-05-17 22:26:12 -0700110 }
111
112 public StatusBarNotification(Parcel in) {
Joe Onorato18e69df2010-05-17 22:26:12 -0700113 this.pkg = in.readString();
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400114 this.opPkg = in.readString();
Joe Onorato18e69df2010-05-17 22:26:12 -0700115 this.id = in.readInt();
116 if (in.readInt() != 0) {
117 this.tag = in.readString();
118 } else {
119 this.tag = null;
120 }
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700121 this.uid = in.readInt();
122 this.initialPid = in.readInt();
Joe Onorato18e69df2010-05-17 22:26:12 -0700123 this.notification = new Notification(in);
Jeff Sharkey6d515712012-09-20 16:06:08 -0700124 this.user = UserHandle.readFromParcel(in);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500125 this.postTime = in.readLong();
Julia Reynoldse46bb372016-03-17 11:05:58 -0400126 if (in.readInt() != 0) {
127 this.overrideGroupKey = in.readString();
128 } else {
129 this.overrideGroupKey = null;
130 }
John Spurlocka4294292014-03-24 18:02:32 -0400131 this.key = key();
Chris Wren1031c972014-07-23 13:11:45 +0000132 this.groupKey = groupKey();
John Spurlocka4294292014-03-24 18:02:32 -0400133 }
134
135 private String key() {
Julia Reynoldse46bb372016-03-17 11:05:58 -0400136 String sbnKey = user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
137 if (overrideGroupKey != null && getNotification().isGroupSummary()) {
138 sbnKey = sbnKey + "|" + overrideGroupKey;
139 }
140 return sbnKey;
Joe Onorato18e69df2010-05-17 22:26:12 -0700141 }
142
Chris Wren1031c972014-07-23 13:11:45 +0000143 private String groupKey() {
Julia Reynoldse46bb372016-03-17 11:05:58 -0400144 if (overrideGroupKey != null) {
145 return user.getIdentifier() + "|" + pkg + "|" + "g:" + overrideGroupKey;
146 }
Chris Wren1031c972014-07-23 13:11:45 +0000147 final String group = getNotification().getGroup();
148 final String sortKey = getNotification().getSortKey();
149 if (group == null && sortKey == null) {
150 // a group of one
151 return key;
152 }
153 return user.getIdentifier() + "|" + pkg + "|" +
154 (group == null
Julia Reynoldsbad42972017-04-25 13:52:49 -0400155 ? "c:" + notification.getChannelId()
Chris Wren1031c972014-07-23 13:11:45 +0000156 : "g:" + group);
157 }
158
Julia Reynoldse46bb372016-03-17 11:05:58 -0400159 /**
160 * Returns true if this notification is part of a group.
161 */
162 public boolean isGroup() {
Chris Wren8a1638f2016-05-02 16:19:14 -0400163 if (overrideGroupKey != null || isAppGroup()) {
164 return true;
165 }
166 return false;
167 }
168
169 /**
170 * Returns true if application asked that this notification be part of a group.
171 * @hide
172 */
173 public boolean isAppGroup() {
174 if (getNotification().getGroup() != null || getNotification().getSortKey() != null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -0400175 return true;
176 }
177 return false;
178 }
179
Joe Onorato18e69df2010-05-17 22:26:12 -0700180 public void writeToParcel(Parcel out, int flags) {
181 out.writeString(this.pkg);
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400182 out.writeString(this.opPkg);
Joe Onorato18e69df2010-05-17 22:26:12 -0700183 out.writeInt(this.id);
184 if (this.tag != null) {
185 out.writeInt(1);
186 out.writeString(this.tag);
187 } else {
188 out.writeInt(0);
189 }
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700190 out.writeInt(this.uid);
191 out.writeInt(this.initialPid);
Joe Onorato18e69df2010-05-17 22:26:12 -0700192 this.notification.writeToParcel(out, flags);
Jeff Sharkey6d515712012-09-20 16:06:08 -0700193 user.writeToParcel(out, flags);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500194
195 out.writeLong(this.postTime);
Julia Reynoldse46bb372016-03-17 11:05:58 -0400196 if (this.overrideGroupKey != null) {
197 out.writeInt(1);
198 out.writeString(this.overrideGroupKey);
199 } else {
200 out.writeInt(0);
201 }
Joe Onorato18e69df2010-05-17 22:26:12 -0700202 }
203
204 public int describeContents() {
205 return 0;
206 }
207
208 public static final Parcelable.Creator<StatusBarNotification> CREATOR
209 = new Parcelable.Creator<StatusBarNotification>()
210 {
211 public StatusBarNotification createFromParcel(Parcel parcel)
212 {
213 return new StatusBarNotification(parcel);
214 }
215
216 public StatusBarNotification[] newArray(int size)
217 {
218 return new StatusBarNotification[size];
219 }
220 };
221
Daniel Sandler1a497d32013-04-18 14:52:45 -0400222 /**
223 * @hide
224 */
225 public StatusBarNotification cloneLight() {
226 final Notification no = new Notification();
227 this.notification.cloneInto(no, false); // light copy
Julia Reynolds924eed12017-01-19 09:52:07 -0500228 return new StatusBarNotification(this.pkg, this.opPkg,
Daniel Sandler1a497d32013-04-18 14:52:45 -0400229 this.id, this.tag, this.uid, this.initialPid,
Julia Reynoldse46bb372016-03-17 11:05:58 -0400230 no, this.user, this.overrideGroupKey, this.postTime);
Daniel Sandler1a497d32013-04-18 14:52:45 -0400231 }
232
Jeff Sharkey6d515712012-09-20 16:06:08 -0700233 @Override
Joe Onorato18e69df2010-05-17 22:26:12 -0700234 public StatusBarNotification clone() {
Julia Reynolds924eed12017-01-19 09:52:07 -0500235 return new StatusBarNotification(this.pkg, this.opPkg,
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500236 this.id, this.tag, this.uid, this.initialPid,
Julia Reynoldse46bb372016-03-17 11:05:58 -0400237 this.notification.clone(), this.user, this.overrideGroupKey, this.postTime);
Joe Onorato18e69df2010-05-17 22:26:12 -0700238 }
239
Jeff Sharkey6d515712012-09-20 16:06:08 -0700240 @Override
Joe Onorato18e69df2010-05-17 22:26:12 -0700241 public String toString() {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500242 return String.format(
Julia Reynoldse46bb372016-03-17 11:05:58 -0400243 "StatusBarNotification(pkg=%s user=%s id=%d tag=%s key=%s: %s)",
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500244 this.pkg, this.user, this.id, this.tag,
Julia Reynoldse46bb372016-03-17 11:05:58 -0400245 this.key, this.notification);
Joe Onorato18e69df2010-05-17 22:26:12 -0700246 }
247
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700248 /** Convenience method to check the notification's flags for
249 * {@link Notification#FLAG_ONGOING_EVENT}.
250 */
Joe Onoratoe345fff2010-05-23 15:18:27 -0400251 public boolean isOngoing() {
252 return (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
253 }
254
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700255 /** Convenience method to check the notification's flags for
256 * either {@link Notification#FLAG_ONGOING_EVENT} or
257 * {@link Notification#FLAG_NO_CLEAR}.
258 */
Joe Onorato5dd11692010-09-27 15:34:04 -0700259 public boolean isClearable() {
260 return ((notification.flags & Notification.FLAG_ONGOING_EVENT) == 0)
261 && ((notification.flags & Notification.FLAG_NO_CLEAR) == 0);
262 }
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400263
Kenny Guya263e4e2014-03-03 18:24:03 +0000264 /**
Julia Reynoldsd5261e12016-12-19 14:14:25 -0500265 * Returns a userid for whom this notification is intended.
Kenny Guya263e4e2014-03-03 18:24:03 +0000266 *
267 * @deprecated Use {@link #getUser()} instead.
268 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700269 @Deprecated
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400270 public int getUserId() {
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700271 return this.user.getIdentifier();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400272 }
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400273
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400274 /** The package that the notification belongs to. */
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400275 public String getPackageName() {
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400276 return pkg;
277 }
278
Scott Main265103202013-05-22 19:00:09 -0700279 /** The id supplied to {@link android.app.NotificationManager#notify(int,Notification)}. */
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400280 public int getId() {
281 return id;
282 }
283
Scott Main265103202013-05-22 19:00:09 -0700284 /** The tag supplied to {@link android.app.NotificationManager#notify(int,Notification)},
285 * or null if no tag was specified. */
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400286 public String getTag() {
287 return tag;
288 }
289
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400290 /**
291 * The notifying app's ({@link #getPackageName()}'s) uid.
292 */
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400293 public int getUid() {
294 return uid;
295 }
296
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400297 /** The package that posted the notification.
298 *<p>
299 * Might be different from {@link #getPackageName()} if the app owning the notification has
300 * a {@link NotificationManager#setNotificationDelegate(String) notification delegate}.
301 */
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400302 public String getOpPkg() {
303 return opPkg;
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400304 }
305
306 /** @hide */
Mathew Inwoode3807372018-08-10 09:51:03 +0100307 @UnsupportedAppUsage
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400308 public int getInitialPid() {
309 return initialPid;
310 }
311
312 /** The {@link android.app.Notification} supplied to
Scott Main265103202013-05-22 19:00:09 -0700313 * {@link android.app.NotificationManager#notify(int,Notification)}. */
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400314 public Notification getNotification() {
315 return notification;
316 }
317
318 /**
319 * The {@link android.os.UserHandle} for whom this notification is intended.
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400320 */
321 public UserHandle getUser() {
322 return user;
323 }
324
325 /** The time (in {@link System#currentTimeMillis} time) the notification was posted,
326 * which may be different than {@link android.app.Notification#when}.
327 */
328 public long getPostTime() {
329 return postTime;
330 }
331
John Spurlocka4294292014-03-24 18:02:32 -0400332 /**
333 * A unique instance key for this notification record.
334 */
335 public String getKey() {
336 return key;
337 }
Chris Wren1031c972014-07-23 13:11:45 +0000338
339 /**
340 * A key that indicates the group with which this message ranks.
341 */
342 public String getGroupKey() {
343 return groupKey;
344 }
Dan Sandler68079d52015-07-22 10:45:30 -0400345
346 /**
Chris Wrenb3921792017-06-01 13:34:46 -0400347 * The ID passed to setGroup(), or the override, or null.
348 * @hide
349 */
350 public String getGroup() {
351 if (overrideGroupKey != null) {
352 return overrideGroupKey;
353 }
354 return getNotification().getGroup();
355 }
356
357 /**
Julia Reynoldse46bb372016-03-17 11:05:58 -0400358 * Sets the override group key.
359 */
360 public void setOverrideGroupKey(String overrideGroupKey) {
361 this.overrideGroupKey = overrideGroupKey;
362 groupKey = groupKey();
363 }
364
365 /**
366 * Returns the override group key.
367 */
368 public String getOverrideGroupKey() {
369 return overrideGroupKey;
370 }
371
372 /**
Dan Sandler68079d52015-07-22 10:45:30 -0400373 * @hide
374 */
Amin Shaikhc3f0b062019-02-12 19:00:17 -0500375 public void clearPackageContext() {
376 mContext = null;
377 }
378
379 /**
380 * @hide
381 */
Mathew Inwoode3807372018-08-10 09:51:03 +0100382 @UnsupportedAppUsage
Dan Sandler68079d52015-07-22 10:45:30 -0400383 public Context getPackageContext(Context context) {
384 if (mContext == null) {
385 try {
386 ApplicationInfo ai = context.getPackageManager()
Amith Yamasani0d1fd8d2016-10-12 14:21:51 -0700387 .getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES,
388 getUserId());
Dan Sandler68079d52015-07-22 10:45:30 -0400389 mContext = context.createApplicationContext(ai,
390 Context.CONTEXT_RESTRICTED);
391 } catch (PackageManager.NameNotFoundException e) {
392 mContext = null;
393 }
394 }
395 if (mContext == null) {
396 mContext = context;
397 }
398 return mContext;
399 }
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200400
401 /**
402 * Returns a LogMaker that contains all basic information of the notification.
403 * @hide
404 */
405 public LogMaker getLogMaker() {
406 if (mLogMaker == null) {
407 // Initialize fields that only change on update (so a new record).
408 mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
409 .setPackageName(getPackageName())
410 .addTaggedData(MetricsEvent.NOTIFICATION_ID, getId())
411 .addTaggedData(MetricsEvent.NOTIFICATION_TAG, getTag())
412 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag());
413 }
414 // Reset fields that can change between updates, or are used by multiple logs.
415 return mLogMaker
416 .clearCategory()
417 .clearType()
418 .clearSubtype()
419 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
420 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
Will Brockman828427e2019-01-28 09:55:45 -0500421 getNotification().isGroupSummary() ? 1 : 0)
422 .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CATEGORY,
423 getNotification().category);
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200424 }
425
426 private String getGroupLogTag() {
427 return shortenTag(getGroup());
428 }
429
430 private String getChannelIdLogTag() {
431 if (notification.getChannelId() == null) {
432 return null;
433 }
434 return shortenTag(notification.getChannelId());
435 }
436
437 // Make logTag with max size MAX_LOG_TAG_LENGTH.
438 // For shorter or equal tags, returns the tag.
439 // For longer tags, truncate the tag and append a hash of the full tag to
440 // fill the maximum size.
441 private String shortenTag(String logTag) {
442 if (logTag == null || logTag.length() <= MAX_LOG_TAG_LENGTH) {
443 return logTag;
444 }
445 String hash = Integer.toHexString(logTag.hashCode());
446 return logTag.substring(0, MAX_LOG_TAG_LENGTH - hash.length() - 1) + "-"
447 + hash;
448 }
Joe Onorato18e69df2010-05-17 22:26:12 -0700449}