blob: 3a644d4cd12a0028e6ade72105cbeff3348af7aa [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
Eyal Posenera9cf9c72018-12-18 16:23:54 +020031import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
32
Daniel Sandler2561b0b2012-02-13 21:04:12 -050033/**
Daniel Sandlerfde19b12013-01-17 00:21:05 -050034 * Class encapsulating a Notification. Sent by the NotificationManagerService to clients including
Daniel Sandler5feceeb2013-03-22 18:29:23 -070035 * the status bar and any {@link android.service.notification.NotificationListenerService}s.
Daniel Sandler2561b0b2012-02-13 21:04:12 -050036 */
Joe Onorato18e69df2010-05-17 22:26:12 -070037public class StatusBarNotification implements Parcelable {
Eyal Posenera9cf9c72018-12-18 16:23:54 +020038 static final int MAX_LOG_TAG_LENGTH = 36;
39
Mathew Inwoode3807372018-08-10 09:51:03 +010040 @UnsupportedAppUsage
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040041 private final String pkg;
Mathew Inwoode3807372018-08-10 09:51:03 +010042 @UnsupportedAppUsage
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040043 private final int id;
Mathew Inwood31755f92018-12-20 13:53:36 +000044 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040045 private final String tag;
John Spurlocka4294292014-03-24 18:02:32 -040046 private final String key;
Julia Reynoldse46bb372016-03-17 11:05:58 -040047 private String groupKey;
48 private String overrideGroupKey;
Daniel Sandler5feceeb2013-03-22 18:29:23 -070049
Mathew Inwoode3807372018-08-10 09:51:03 +010050 @UnsupportedAppUsage
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040051 private final int uid;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -040052 private final String opPkg;
Mathew Inwood31755f92018-12-20 13:53:36 +000053 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040054 private final int initialPid;
Mathew Inwood31755f92018-12-20 13:53:36 +000055 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040056 private final Notification notification;
Mathew Inwood31755f92018-12-20 13:53:36 +000057 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040058 private final UserHandle user;
Mathew Inwood31755f92018-12-20 13:53:36 +000059 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -040060 private final long postTime;
Jeff Sharkey6d515712012-09-20 16:06:08 -070061
Dan Sandler68079d52015-07-22 10:45:30 -040062 private Context mContext; // used for inflation & icon expansion
Daniel Sandler5feceeb2013-03-22 18:29:23 -070063
Eyal Posenera9cf9c72018-12-18 16:23:54 +020064 // Contains the basic logging data of the notification.
65 private LogMaker mLogMaker;
66
Daniel Sandler5feceeb2013-03-22 18:29:23 -070067 /** @hide */
Julia Reynolds924eed12017-01-19 09:52:07 -050068 public StatusBarNotification(String pkg, String opPkg, int id,
Julia Reynolds423b9fc2016-11-09 09:51:08 -050069 String tag, int uid, int initialPid, Notification notification, UserHandle user,
70 String overrideGroupKey, long postTime) {
Julia Reynoldse46bb372016-03-17 11:05:58 -040071 if (pkg == null) throw new NullPointerException();
72 if (notification == null) throw new NullPointerException();
73
74 this.pkg = pkg;
75 this.opPkg = opPkg;
76 this.id = id;
77 this.tag = tag;
78 this.uid = uid;
79 this.initialPid = initialPid;
80 this.notification = notification;
81 this.user = user;
82 this.postTime = postTime;
83 this.overrideGroupKey = overrideGroupKey;
84 this.key = key();
85 this.groupKey = groupKey();
86 }
87
Julia Reynoldsa11d0b12017-02-16 15:01:36 -050088 /**
89 * @deprecated Non-system apps should not need to create StatusBarNotifications.
90 */
Julia Reynolds423b9fc2016-11-09 09:51:08 -050091 @Deprecated
Christoph Studer8fd7f1e2014-04-11 17:35:05 -040092 public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
Daniel Sandlerfde19b12013-01-17 00:21:05 -050093 int initialPid, int score, Notification notification, UserHandle user,
94 long postTime) {
Joe Onorato18e69df2010-05-17 22:26:12 -070095 if (pkg == null) throw new NullPointerException();
96 if (notification == null) throw new NullPointerException();
97
98 this.pkg = pkg;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -040099 this.opPkg = opPkg;
Joe Onorato18e69df2010-05-17 22:26:12 -0700100 this.id = id;
101 this.tag = tag;
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700102 this.uid = uid;
103 this.initialPid = initialPid;
Joe Onorato18e69df2010-05-17 22:26:12 -0700104 this.notification = notification;
Jeff Sharkey6d515712012-09-20 16:06:08 -0700105 this.user = user;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500106 this.postTime = postTime;
John Spurlocka4294292014-03-24 18:02:32 -0400107 this.key = key();
Chris Wren1031c972014-07-23 13:11:45 +0000108 this.groupKey = groupKey();
Joe Onorato18e69df2010-05-17 22:26:12 -0700109 }
110
111 public StatusBarNotification(Parcel in) {
Joe Onorato18e69df2010-05-17 22:26:12 -0700112 this.pkg = in.readString();
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400113 this.opPkg = in.readString();
Joe Onorato18e69df2010-05-17 22:26:12 -0700114 this.id = in.readInt();
115 if (in.readInt() != 0) {
116 this.tag = in.readString();
117 } else {
118 this.tag = null;
119 }
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700120 this.uid = in.readInt();
121 this.initialPid = in.readInt();
Joe Onorato18e69df2010-05-17 22:26:12 -0700122 this.notification = new Notification(in);
Jeff Sharkey6d515712012-09-20 16:06:08 -0700123 this.user = UserHandle.readFromParcel(in);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500124 this.postTime = in.readLong();
Julia Reynoldse46bb372016-03-17 11:05:58 -0400125 if (in.readInt() != 0) {
126 this.overrideGroupKey = in.readString();
127 } else {
128 this.overrideGroupKey = null;
129 }
John Spurlocka4294292014-03-24 18:02:32 -0400130 this.key = key();
Chris Wren1031c972014-07-23 13:11:45 +0000131 this.groupKey = groupKey();
John Spurlocka4294292014-03-24 18:02:32 -0400132 }
133
134 private String key() {
Julia Reynoldse46bb372016-03-17 11:05:58 -0400135 String sbnKey = user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
136 if (overrideGroupKey != null && getNotification().isGroupSummary()) {
137 sbnKey = sbnKey + "|" + overrideGroupKey;
138 }
139 return sbnKey;
Joe Onorato18e69df2010-05-17 22:26:12 -0700140 }
141
Chris Wren1031c972014-07-23 13:11:45 +0000142 private String groupKey() {
Julia Reynoldse46bb372016-03-17 11:05:58 -0400143 if (overrideGroupKey != null) {
144 return user.getIdentifier() + "|" + pkg + "|" + "g:" + overrideGroupKey;
145 }
Chris Wren1031c972014-07-23 13:11:45 +0000146 final String group = getNotification().getGroup();
147 final String sortKey = getNotification().getSortKey();
148 if (group == null && sortKey == null) {
149 // a group of one
150 return key;
151 }
152 return user.getIdentifier() + "|" + pkg + "|" +
153 (group == null
Julia Reynoldsbad42972017-04-25 13:52:49 -0400154 ? "c:" + notification.getChannelId()
Chris Wren1031c972014-07-23 13:11:45 +0000155 : "g:" + group);
156 }
157
Julia Reynoldse46bb372016-03-17 11:05:58 -0400158 /**
159 * Returns true if this notification is part of a group.
160 */
161 public boolean isGroup() {
Chris Wren8a1638f2016-05-02 16:19:14 -0400162 if (overrideGroupKey != null || isAppGroup()) {
163 return true;
164 }
165 return false;
166 }
167
168 /**
169 * Returns true if application asked that this notification be part of a group.
170 * @hide
171 */
172 public boolean isAppGroup() {
173 if (getNotification().getGroup() != null || getNotification().getSortKey() != null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -0400174 return true;
175 }
176 return false;
177 }
178
Joe Onorato18e69df2010-05-17 22:26:12 -0700179 public void writeToParcel(Parcel out, int flags) {
180 out.writeString(this.pkg);
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400181 out.writeString(this.opPkg);
Joe Onorato18e69df2010-05-17 22:26:12 -0700182 out.writeInt(this.id);
183 if (this.tag != null) {
184 out.writeInt(1);
185 out.writeString(this.tag);
186 } else {
187 out.writeInt(0);
188 }
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700189 out.writeInt(this.uid);
190 out.writeInt(this.initialPid);
Joe Onorato18e69df2010-05-17 22:26:12 -0700191 this.notification.writeToParcel(out, flags);
Jeff Sharkey6d515712012-09-20 16:06:08 -0700192 user.writeToParcel(out, flags);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500193
194 out.writeLong(this.postTime);
Julia Reynoldse46bb372016-03-17 11:05:58 -0400195 if (this.overrideGroupKey != null) {
196 out.writeInt(1);
197 out.writeString(this.overrideGroupKey);
198 } else {
199 out.writeInt(0);
200 }
Joe Onorato18e69df2010-05-17 22:26:12 -0700201 }
202
203 public int describeContents() {
204 return 0;
205 }
206
207 public static final Parcelable.Creator<StatusBarNotification> CREATOR
208 = new Parcelable.Creator<StatusBarNotification>()
209 {
210 public StatusBarNotification createFromParcel(Parcel parcel)
211 {
212 return new StatusBarNotification(parcel);
213 }
214
215 public StatusBarNotification[] newArray(int size)
216 {
217 return new StatusBarNotification[size];
218 }
219 };
220
Daniel Sandler1a497d32013-04-18 14:52:45 -0400221 /**
222 * @hide
223 */
224 public StatusBarNotification cloneLight() {
225 final Notification no = new Notification();
226 this.notification.cloneInto(no, false); // light copy
Julia Reynolds924eed12017-01-19 09:52:07 -0500227 return new StatusBarNotification(this.pkg, this.opPkg,
Daniel Sandler1a497d32013-04-18 14:52:45 -0400228 this.id, this.tag, this.uid, this.initialPid,
Julia Reynoldse46bb372016-03-17 11:05:58 -0400229 no, this.user, this.overrideGroupKey, this.postTime);
Daniel Sandler1a497d32013-04-18 14:52:45 -0400230 }
231
Jeff Sharkey6d515712012-09-20 16:06:08 -0700232 @Override
Joe Onorato18e69df2010-05-17 22:26:12 -0700233 public StatusBarNotification clone() {
Julia Reynolds924eed12017-01-19 09:52:07 -0500234 return new StatusBarNotification(this.pkg, this.opPkg,
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500235 this.id, this.tag, this.uid, this.initialPid,
Julia Reynoldse46bb372016-03-17 11:05:58 -0400236 this.notification.clone(), this.user, this.overrideGroupKey, this.postTime);
Joe Onorato18e69df2010-05-17 22:26:12 -0700237 }
238
Jeff Sharkey6d515712012-09-20 16:06:08 -0700239 @Override
Joe Onorato18e69df2010-05-17 22:26:12 -0700240 public String toString() {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500241 return String.format(
Julia Reynoldse46bb372016-03-17 11:05:58 -0400242 "StatusBarNotification(pkg=%s user=%s id=%d tag=%s key=%s: %s)",
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500243 this.pkg, this.user, this.id, this.tag,
Julia Reynoldse46bb372016-03-17 11:05:58 -0400244 this.key, this.notification);
Joe Onorato18e69df2010-05-17 22:26:12 -0700245 }
246
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700247 /** Convenience method to check the notification's flags for
248 * {@link Notification#FLAG_ONGOING_EVENT}.
249 */
Joe Onoratoe345fff2010-05-23 15:18:27 -0400250 public boolean isOngoing() {
251 return (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
252 }
253
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700254 /** Convenience method to check the notification's flags for
255 * either {@link Notification#FLAG_ONGOING_EVENT} or
256 * {@link Notification#FLAG_NO_CLEAR}.
257 */
Joe Onorato5dd11692010-09-27 15:34:04 -0700258 public boolean isClearable() {
259 return ((notification.flags & Notification.FLAG_ONGOING_EVENT) == 0)
260 && ((notification.flags & Notification.FLAG_NO_CLEAR) == 0);
261 }
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400262
Kenny Guya263e4e2014-03-03 18:24:03 +0000263 /**
Julia Reynoldsd5261e12016-12-19 14:14:25 -0500264 * Returns a userid for whom this notification is intended.
Kenny Guya263e4e2014-03-03 18:24:03 +0000265 *
266 * @deprecated Use {@link #getUser()} instead.
267 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700268 @Deprecated
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400269 public int getUserId() {
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700270 return this.user.getIdentifier();
Daniel Sandlerb9301c32012-08-14 15:08:24 -0400271 }
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400272
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400273 /** The package that the notification belongs to. */
Daniel Sandler4f91efd2013-04-25 16:38:41 -0400274 public String getPackageName() {
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400275 return pkg;
276 }
277
Scott Main265103202013-05-22 19:00:09 -0700278 /** The id supplied to {@link android.app.NotificationManager#notify(int,Notification)}. */
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400279 public int getId() {
280 return id;
281 }
282
Scott Main265103202013-05-22 19:00:09 -0700283 /** The tag supplied to {@link android.app.NotificationManager#notify(int,Notification)},
284 * or null if no tag was specified. */
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400285 public String getTag() {
286 return tag;
287 }
288
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400289 /**
290 * The notifying app's ({@link #getPackageName()}'s) uid.
291 */
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400292 public int getUid() {
293 return uid;
294 }
295
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400296 /** The package that posted the notification.
297 *<p>
298 * Might be different from {@link #getPackageName()} if the app owning the notification has
299 * a {@link NotificationManager#setNotificationDelegate(String) notification delegate}.
300 */
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400301 public String getOpPkg() {
302 return opPkg;
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400303 }
304
305 /** @hide */
Mathew Inwoode3807372018-08-10 09:51:03 +0100306 @UnsupportedAppUsage
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400307 public int getInitialPid() {
308 return initialPid;
309 }
310
311 /** The {@link android.app.Notification} supplied to
Scott Main265103202013-05-22 19:00:09 -0700312 * {@link android.app.NotificationManager#notify(int,Notification)}. */
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400313 public Notification getNotification() {
314 return notification;
315 }
316
317 /**
318 * The {@link android.os.UserHandle} for whom this notification is intended.
Daniel Sandlere6f7f2e2013-04-25 15:44:16 -0400319 */
320 public UserHandle getUser() {
321 return user;
322 }
323
324 /** The time (in {@link System#currentTimeMillis} time) the notification was posted,
325 * which may be different than {@link android.app.Notification#when}.
326 */
327 public long getPostTime() {
328 return postTime;
329 }
330
John Spurlocka4294292014-03-24 18:02:32 -0400331 /**
332 * A unique instance key for this notification record.
333 */
334 public String getKey() {
335 return key;
336 }
Chris Wren1031c972014-07-23 13:11:45 +0000337
338 /**
339 * A key that indicates the group with which this message ranks.
340 */
341 public String getGroupKey() {
342 return groupKey;
343 }
Dan Sandler68079d52015-07-22 10:45:30 -0400344
345 /**
Chris Wrenb3921792017-06-01 13:34:46 -0400346 * The ID passed to setGroup(), or the override, or null.
347 * @hide
348 */
349 public String getGroup() {
350 if (overrideGroupKey != null) {
351 return overrideGroupKey;
352 }
353 return getNotification().getGroup();
354 }
355
356 /**
Julia Reynoldse46bb372016-03-17 11:05:58 -0400357 * Sets the override group key.
358 */
359 public void setOverrideGroupKey(String overrideGroupKey) {
360 this.overrideGroupKey = overrideGroupKey;
361 groupKey = groupKey();
362 }
363
364 /**
365 * Returns the override group key.
366 */
367 public String getOverrideGroupKey() {
368 return overrideGroupKey;
369 }
370
371 /**
Dan Sandler68079d52015-07-22 10:45:30 -0400372 * @hide
373 */
Mathew Inwoode3807372018-08-10 09:51:03 +0100374 @UnsupportedAppUsage
Dan Sandler68079d52015-07-22 10:45:30 -0400375 public Context getPackageContext(Context context) {
376 if (mContext == null) {
377 try {
378 ApplicationInfo ai = context.getPackageManager()
Amith Yamasani0d1fd8d2016-10-12 14:21:51 -0700379 .getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES,
380 getUserId());
Dan Sandler68079d52015-07-22 10:45:30 -0400381 mContext = context.createApplicationContext(ai,
382 Context.CONTEXT_RESTRICTED);
383 } catch (PackageManager.NameNotFoundException e) {
384 mContext = null;
385 }
386 }
387 if (mContext == null) {
388 mContext = context;
389 }
390 return mContext;
391 }
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200392
393 /**
394 * Returns a LogMaker that contains all basic information of the notification.
395 * @hide
396 */
397 public LogMaker getLogMaker() {
398 if (mLogMaker == null) {
399 // Initialize fields that only change on update (so a new record).
400 mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
401 .setPackageName(getPackageName())
402 .addTaggedData(MetricsEvent.NOTIFICATION_ID, getId())
403 .addTaggedData(MetricsEvent.NOTIFICATION_TAG, getTag())
404 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag());
405 }
406 // Reset fields that can change between updates, or are used by multiple logs.
407 return mLogMaker
408 .clearCategory()
409 .clearType()
410 .clearSubtype()
411 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
412 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
413 getNotification().isGroupSummary() ? 1 : 0);
414 }
415
416 private String getGroupLogTag() {
417 return shortenTag(getGroup());
418 }
419
420 private String getChannelIdLogTag() {
421 if (notification.getChannelId() == null) {
422 return null;
423 }
424 return shortenTag(notification.getChannelId());
425 }
426
427 // Make logTag with max size MAX_LOG_TAG_LENGTH.
428 // For shorter or equal tags, returns the tag.
429 // For longer tags, truncate the tag and append a hash of the full tag to
430 // fill the maximum size.
431 private String shortenTag(String logTag) {
432 if (logTag == null || logTag.length() <= MAX_LOG_TAG_LENGTH) {
433 return logTag;
434 }
435 String hash = Integer.toHexString(logTag.hashCode());
436 return logTag.substring(0, MAX_LOG_TAG_LENGTH - hash.length() - 1) + "-"
437 + hash;
438 }
Joe Onorato18e69df2010-05-17 22:26:12 -0700439}