Home | History | Annotate | Download | only in notification
      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