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 final String groupKey;
37 
38     private final int uid;
39     private final String opPkg;
40     private final int initialPid;
41     private final Notification notification;
42     private final UserHandle user;
43     private final long postTime;
44 
45     private final int score;
46     private Context mContext; // used for inflation & icon expansion
47 
48     /** @hide */
StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid, int initialPid, int score, Notification notification, UserHandle user)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 
StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid, int initialPid, int score, Notification notification, UserHandle user, long postTime)55     public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
56             int initialPid, int score, Notification notification, UserHandle user,
57             long postTime) {
58         if (pkg == null) throw new NullPointerException();
59         if (notification == null) throw new NullPointerException();
60 
61         this.pkg = pkg;
62         this.opPkg = opPkg;
63         this.id = id;
64         this.tag = tag;
65         this.uid = uid;
66         this.initialPid = initialPid;
67         this.score = score;
68         this.notification = notification;
69         this.user = user;
70         this.postTime = postTime;
71         this.key = key();
72         this.groupKey = groupKey();
73     }
74 
StatusBarNotification(Parcel in)75     public StatusBarNotification(Parcel in) {
76         this.pkg = in.readString();
77         this.opPkg = in.readString();
78         this.id = in.readInt();
79         if (in.readInt() != 0) {
80             this.tag = in.readString();
81         } else {
82             this.tag = null;
83         }
84         this.uid = in.readInt();
85         this.initialPid = in.readInt();
86         this.score = in.readInt();
87         this.notification = new Notification(in);
88         this.user = UserHandle.readFromParcel(in);
89         this.postTime = in.readLong();
90         this.key = key();
91         this.groupKey = groupKey();
92     }
93 
key()94     private String key() {
95         return user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
96     }
97 
groupKey()98     private String groupKey() {
99         final String group = getNotification().getGroup();
100         final String sortKey = getNotification().getSortKey();
101         if (group == null && sortKey == null) {
102             // a group of one
103             return key;
104         }
105         return user.getIdentifier() + "|" + pkg + "|" +
106                 (group == null
107                         ? "p:" + notification.priority
108                         : "g:" + group);
109     }
110 
writeToParcel(Parcel out, int flags)111     public void writeToParcel(Parcel out, int flags) {
112         out.writeString(this.pkg);
113         out.writeString(this.opPkg);
114         out.writeInt(this.id);
115         if (this.tag != null) {
116             out.writeInt(1);
117             out.writeString(this.tag);
118         } else {
119             out.writeInt(0);
120         }
121         out.writeInt(this.uid);
122         out.writeInt(this.initialPid);
123         out.writeInt(this.score);
124         this.notification.writeToParcel(out, flags);
125         user.writeToParcel(out, flags);
126 
127         out.writeLong(this.postTime);
128     }
129 
describeContents()130     public int describeContents() {
131         return 0;
132     }
133 
134     public static final Parcelable.Creator<StatusBarNotification> CREATOR
135             = new Parcelable.Creator<StatusBarNotification>()
136     {
137         public StatusBarNotification createFromParcel(Parcel parcel)
138         {
139             return new StatusBarNotification(parcel);
140         }
141 
142         public StatusBarNotification[] newArray(int size)
143         {
144             return new StatusBarNotification[size];
145         }
146     };
147 
148     /**
149      * @hide
150      */
cloneLight()151     public StatusBarNotification cloneLight() {
152         final Notification no = new Notification();
153         this.notification.cloneInto(no, false); // light copy
154         return new StatusBarNotification(this.pkg, this.opPkg,
155                 this.id, this.tag, this.uid, this.initialPid,
156                 this.score, no, this.user, this.postTime);
157     }
158 
159     @Override
clone()160     public StatusBarNotification clone() {
161         return new StatusBarNotification(this.pkg, this.opPkg,
162                 this.id, this.tag, this.uid, this.initialPid,
163                 this.score, this.notification.clone(), this.user, this.postTime);
164     }
165 
166     @Override
toString()167     public String toString() {
168         return String.format(
169                 "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)",
170                 this.pkg, this.user, this.id, this.tag,
171                 this.score, this.key, this.notification);
172     }
173 
174     /** Convenience method to check the notification's flags for
175      * {@link Notification#FLAG_ONGOING_EVENT}.
176      */
isOngoing()177     public boolean isOngoing() {
178         return (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
179     }
180 
181     /** Convenience method to check the notification's flags for
182      * either {@link Notification#FLAG_ONGOING_EVENT} or
183      * {@link Notification#FLAG_NO_CLEAR}.
184      */
isClearable()185     public boolean isClearable() {
186         return ((notification.flags & Notification.FLAG_ONGOING_EVENT) == 0)
187                 && ((notification.flags & Notification.FLAG_NO_CLEAR) == 0);
188     }
189 
190     /**
191      * Returns a userHandle for the instance of the app that posted this notification.
192      *
193      * @deprecated Use {@link #getUser()} instead.
194      */
getUserId()195     public int getUserId() {
196         return this.user.getIdentifier();
197     }
198 
199     /** The package of the app that posted the notification. */
getPackageName()200     public String getPackageName() {
201         return pkg;
202     }
203 
204     /** The id supplied to {@link android.app.NotificationManager#notify(int,Notification)}. */
getId()205     public int getId() {
206         return id;
207     }
208 
209     /** The tag supplied to {@link android.app.NotificationManager#notify(int,Notification)},
210      * or null if no tag was specified. */
getTag()211     public String getTag() {
212         return tag;
213     }
214 
215     /** The notifying app's calling uid. @hide */
getUid()216     public int getUid() {
217         return uid;
218     }
219 
220     /** The package used for AppOps tracking. @hide */
getOpPkg()221     public String getOpPkg() {
222         return opPkg;
223     }
224 
225     /** @hide */
getInitialPid()226     public int getInitialPid() {
227         return initialPid;
228     }
229 
230     /** The {@link android.app.Notification} supplied to
231      * {@link android.app.NotificationManager#notify(int,Notification)}. */
getNotification()232     public Notification getNotification() {
233         return notification;
234     }
235 
236     /**
237      * The {@link android.os.UserHandle} for whom this notification is intended.
238      */
getUser()239     public UserHandle getUser() {
240         return user;
241     }
242 
243     /** The time (in {@link System#currentTimeMillis} time) the notification was posted,
244      * which may be different than {@link android.app.Notification#when}.
245      */
getPostTime()246     public long getPostTime() {
247         return postTime;
248     }
249 
250     /** @hide */
getScore()251     public int getScore() {
252         return score;
253     }
254 
255     /**
256      * A unique instance key for this notification record.
257      */
getKey()258     public String getKey() {
259         return key;
260     }
261 
262     /**
263      * A key that indicates the group with which this message ranks.
264      */
getGroupKey()265     public String getGroupKey() {
266         return groupKey;
267     }
268 
269     /**
270      * @hide
271      */
getPackageContext(Context context)272     public Context getPackageContext(Context context) {
273         if (mContext == null) {
274             try {
275                 ApplicationInfo ai = context.getPackageManager()
276                         .getApplicationInfo(pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
277                 mContext = context.createApplicationContext(ai,
278                         Context.CONTEXT_RESTRICTED);
279             } catch (PackageManager.NameNotFoundException e) {
280                 mContext = null;
281             }
282         }
283         if (mContext == null) {
284             mContext = context;
285         }
286         return mContext;
287     }
288 }
289