1 /* 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 17 package android.service.notification; 18 19 import android.app.Notification; 20 import android.app.NotificationChannel; 21 import android.content.Context; 22 import android.content.pm.ApplicationInfo; 23 import android.content.pm.PackageManager; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.os.UserHandle; 27 28 /** 29 * Class encapsulating a Notification. Sent by the NotificationManagerService to clients including 30 * the status bar and any {@link android.service.notification.NotificationListenerService}s. 31 */ 32 public class StatusBarNotification implements Parcelable { 33 private final String pkg; 34 private final int id; 35 private final String tag; 36 private final String key; 37 private String groupKey; 38 private String overrideGroupKey; 39 40 private final int uid; 41 private final String opPkg; 42 private final int initialPid; 43 private final Notification notification; 44 private final UserHandle user; 45 private final long postTime; 46 47 private Context mContext; // used for inflation & icon expansion 48 49 /** @hide */ 50 public StatusBarNotification(String pkg, String opPkg, int id, 51 String tag, int uid, int initialPid, Notification notification, UserHandle user, 52 String overrideGroupKey, long postTime) { 53 if (pkg == null) throw new NullPointerException(); 54 if (notification == null) throw new NullPointerException(); 55 56 this.pkg = pkg; 57 this.opPkg = opPkg; 58 this.id = id; 59 this.tag = tag; 60 this.uid = uid; 61 this.initialPid = initialPid; 62 this.notification = notification; 63 this.user = user; 64 this.postTime = postTime; 65 this.overrideGroupKey = overrideGroupKey; 66 this.key = key(); 67 this.groupKey = groupKey(); 68 } 69 70 /** 71 * @deprecated Non-system apps should not need to create StatusBarNotifications. 72 */ 73 @Deprecated 74 public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid, 75 int initialPid, int score, Notification notification, UserHandle user, 76 long postTime) { 77 if (pkg == null) throw new NullPointerException(); 78 if (notification == null) throw new NullPointerException(); 79 80 this.pkg = pkg; 81 this.opPkg = opPkg; 82 this.id = id; 83 this.tag = tag; 84 this.uid = uid; 85 this.initialPid = initialPid; 86 this.notification = notification; 87 this.user = user; 88 this.postTime = postTime; 89 this.key = key(); 90 this.groupKey = groupKey(); 91 } 92 93 public StatusBarNotification(Parcel in) { 94 this.pkg = in.readString(); 95 this.opPkg = in.readString(); 96 this.id = in.readInt(); 97 if (in.readInt() != 0) { 98 this.tag = in.readString(); 99 } else { 100 this.tag = null; 101 } 102 this.uid = in.readInt(); 103 this.initialPid = in.readInt(); 104 this.notification = new Notification(in); 105 this.user = UserHandle.readFromParcel(in); 106 this.postTime = in.readLong(); 107 if (in.readInt() != 0) { 108 this.overrideGroupKey = in.readString(); 109 } else { 110 this.overrideGroupKey = null; 111 } 112 this.key = key(); 113 this.groupKey = groupKey(); 114 } 115 116 private String key() { 117 String sbnKey = user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid; 118 if (overrideGroupKey != null && getNotification().isGroupSummary()) { 119 sbnKey = sbnKey + "|" + overrideGroupKey; 120 } 121 return sbnKey; 122 } 123 124 private String groupKey() { 125 if (overrideGroupKey != null) { 126 return user.getIdentifier() + "|" + pkg + "|" + "g:" + overrideGroupKey; 127 } 128 final String group = getNotification().getGroup(); 129 final String sortKey = getNotification().getSortKey(); 130 if (group == null && sortKey == null) { 131 // a group of one 132 return key; 133 } 134 return user.getIdentifier() + "|" + pkg + "|" + 135 (group == null 136 ? "c:" + notification.getChannelId() 137 : "g:" + group); 138 } 139 140 /** 141 * Returns true if this notification is part of a group. 142 */ 143 public boolean isGroup() { 144 if (overrideGroupKey != null || isAppGroup()) { 145 return true; 146 } 147 return false; 148 } 149 150 /** 151 * Returns true if application asked that this notification be part of a group. 152 * @hide 153 */ 154 public boolean isAppGroup() { 155 if (getNotification().getGroup() != null || getNotification().getSortKey() != null) { 156 return true; 157 } 158 return false; 159 } 160 161 public void writeToParcel(Parcel out, int flags) { 162 out.writeString(this.pkg); 163 out.writeString(this.opPkg); 164 out.writeInt(this.id); 165 if (this.tag != null) { 166 out.writeInt(1); 167 out.writeString(this.tag); 168 } else { 169 out.writeInt(0); 170 } 171 out.writeInt(this.uid); 172 out.writeInt(this.initialPid); 173 this.notification.writeToParcel(out, flags); 174 user.writeToParcel(out, flags); 175 176 out.writeLong(this.postTime); 177 if (this.overrideGroupKey != null) { 178 out.writeInt(1); 179 out.writeString(this.overrideGroupKey); 180 } else { 181 out.writeInt(0); 182 } 183 } 184 185 public int describeContents() { 186 return 0; 187 } 188 189 public static final Parcelable.Creator<StatusBarNotification> CREATOR 190 = new Parcelable.Creator<StatusBarNotification>() 191 { 192 public StatusBarNotification createFromParcel(Parcel parcel) 193 { 194 return new StatusBarNotification(parcel); 195 } 196 197 public StatusBarNotification[] newArray(int size) 198 { 199 return new StatusBarNotification[size]; 200 } 201 }; 202 203 /** 204 * @hide 205 */ 206 public StatusBarNotification cloneLight() { 207 final Notification no = new Notification(); 208 this.notification.cloneInto(no, false); // light copy 209 return new StatusBarNotification(this.pkg, this.opPkg, 210 this.id, this.tag, this.uid, this.initialPid, 211 no, this.user, this.overrideGroupKey, this.postTime); 212 } 213 214 @Override 215 public StatusBarNotification clone() { 216 return new StatusBarNotification(this.pkg, this.opPkg, 217 this.id, this.tag, this.uid, this.initialPid, 218 this.notification.clone(), this.user, this.overrideGroupKey, this.postTime); 219 } 220 221 @Override 222 public String toString() { 223 return String.format( 224 "StatusBarNotification(pkg=%s user=%s id=%d tag=%s key=%s: %s)", 225 this.pkg, this.user, this.id, this.tag, 226 this.key, this.notification); 227 } 228 229 /** Convenience method to check the notification's flags for 230 * {@link Notification#FLAG_ONGOING_EVENT}. 231 */ 232 public boolean isOngoing() { 233 return (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0; 234 } 235 236 /** Convenience method to check the notification's flags for 237 * either {@link Notification#FLAG_ONGOING_EVENT} or 238 * {@link Notification#FLAG_NO_CLEAR}. 239 */ 240 public boolean isClearable() { 241 return ((notification.flags & Notification.FLAG_ONGOING_EVENT) == 0) 242 && ((notification.flags & Notification.FLAG_NO_CLEAR) == 0); 243 } 244 245 /** 246 * Returns a userid for whom this notification is intended. 247 * 248 * @deprecated Use {@link #getUser()} instead. 249 */ 250 @Deprecated 251 public int getUserId() { 252 return this.user.getIdentifier(); 253 } 254 255 /** The package of the app that posted the notification. */ 256 public String getPackageName() { 257 return pkg; 258 } 259 260 /** The id supplied to {@link android.app.NotificationManager#notify(int,Notification)}. */ 261 public int getId() { 262 return id; 263 } 264 265 /** The tag supplied to {@link android.app.NotificationManager#notify(int,Notification)}, 266 * or null if no tag was specified. */ 267 public String getTag() { 268 return tag; 269 } 270 271 /** The notifying app's calling uid. @hide */ 272 public int getUid() { 273 return uid; 274 } 275 276 /** The package used for AppOps tracking. @hide */ 277 public String getOpPkg() { 278 return opPkg; 279 } 280 281 /** @hide */ 282 public int getInitialPid() { 283 return initialPid; 284 } 285 286 /** The {@link android.app.Notification} supplied to 287 * {@link android.app.NotificationManager#notify(int,Notification)}. */ 288 public Notification getNotification() { 289 return notification; 290 } 291 292 /** 293 * The {@link android.os.UserHandle} for whom this notification is intended. 294 */ 295 public UserHandle getUser() { 296 return user; 297 } 298 299 /** The time (in {@link System#currentTimeMillis} time) the notification was posted, 300 * which may be different than {@link android.app.Notification#when}. 301 */ 302 public long getPostTime() { 303 return postTime; 304 } 305 306 /** 307 * A unique instance key for this notification record. 308 */ 309 public String getKey() { 310 return key; 311 } 312 313 /** 314 * A key that indicates the group with which this message ranks. 315 */ 316 public String getGroupKey() { 317 return groupKey; 318 } 319 320 /** 321 * The ID passed to setGroup(), or the override, or null. 322 * @hide 323 */ 324 public String getGroup() { 325 if (overrideGroupKey != null) { 326 return overrideGroupKey; 327 } 328 return getNotification().getGroup(); 329 } 330 331 /** 332 * Sets the override group key. 333 */ 334 public void setOverrideGroupKey(String overrideGroupKey) { 335 this.overrideGroupKey = overrideGroupKey; 336 groupKey = groupKey(); 337 } 338 339 /** 340 * Returns the override group key. 341 */ 342 public String getOverrideGroupKey() { 343 return overrideGroupKey; 344 } 345 346 /** 347 * @hide 348 */ 349 public Context getPackageContext(Context context) { 350 if (mContext == null) { 351 try { 352 ApplicationInfo ai = context.getPackageManager() 353 .getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES, 354 getUserId()); 355 mContext = context.createApplicationContext(ai, 356 Context.CONTEXT_RESTRICTED); 357 } catch (PackageManager.NameNotFoundException e) { 358 mContext = null; 359 } 360 } 361 if (mContext == null) { 362 mContext = context; 363 } 364 return mContext; 365 } 366 } 367