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