diff options
10 files changed, 572 insertions, 252 deletions
diff --git a/api/current.txt b/api/current.txt index 2037515e5632..5ec6322cea34 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3626,12 +3626,22 @@ package android.app {      field public static final int DEFAULT_VIBRATE = 2; // 0x2      field public static final int FLAG_AUTO_CANCEL = 16; // 0x10      field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40 -    field public static final int FLAG_HIGH_PRIORITY = 128; // 0x80 +    field public static final deprecated int FLAG_HIGH_PRIORITY = 128; // 0x80      field public static final int FLAG_INSISTENT = 4; // 0x4      field public static final int FLAG_NO_CLEAR = 32; // 0x20      field public static final int FLAG_ONGOING_EVENT = 2; // 0x2      field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8      field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1 +    field public static final java.lang.String KIND_CALL = "android.call"; +    field public static final java.lang.String KIND_EMAIL = "android.email"; +    field public static final java.lang.String KIND_EVENT = "android.event"; +    field public static final java.lang.String KIND_MESSAGE = "android.message"; +    field public static final java.lang.String KIND_PROMO = "android.promo"; +    field public static final int PRIORITY_DEFAULT = 0; // 0x0 +    field public static final int PRIORITY_HIGH = 1; // 0x1 +    field public static final int PRIORITY_LOW = -1; // 0xffffffff +    field public static final int PRIORITY_MAX = 2; // 0x2 +    field public static final int PRIORITY_MIN = -2; // 0xfffffffe      field public static final int STREAM_DEFAULT = -1; // 0xffffffff      field public int audioStreamType;      field public android.app.PendingIntent contentIntent; @@ -3642,11 +3652,13 @@ package android.app {      field public android.app.PendingIntent fullScreenIntent;      field public int icon;      field public int iconLevel; +    field public java.lang.String[] kind;      field public android.graphics.Bitmap largeIcon;      field public int ledARGB;      field public int ledOffMS;      field public int ledOnMS;      field public int number; +    field public int priority;      field public android.net.Uri sound;      field public java.lang.CharSequence tickerText;      field public android.widget.RemoteViews tickerView; @@ -3656,6 +3668,7 @@ package android.app {    public static class Notification.Builder {      ctor public Notification.Builder(android.content.Context); +    method public android.app.Notification.Builder addKind(java.lang.String);      method public android.app.Notification getNotification();      method public android.app.Notification.Builder setAutoCancel(boolean);      method public android.app.Notification.Builder setContent(android.widget.RemoteViews); @@ -3671,6 +3684,7 @@ package android.app {      method public android.app.Notification.Builder setNumber(int);      method public android.app.Notification.Builder setOngoing(boolean);      method public android.app.Notification.Builder setOnlyAlertOnce(boolean); +    method public android.app.Notification.Builder setPriority(int);      method public android.app.Notification.Builder setProgress(int, int, boolean);      method public android.app.Notification.Builder setSmallIcon(int);      method public android.app.Notification.Builder setSmallIcon(int, int); diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 2420b846514b..4d5238c582f7 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -33,7 +33,6 @@ interface INotificationManager      void enqueueToast(String pkg, ITransientNotification callback, int duration);      void cancelToast(String pkg, ITransientNotification callback);      void enqueueNotificationWithTag(String pkg, String tag, int id, in Notification notification, inout int[] idReceived); -    void enqueueNotificationWithTagPriority(String pkg, String tag, int id, int priority, in Notification notification, inout int[] idReceived);      void cancelNotificationWithTag(String pkg, String tag, int id);  } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index d569e2071463..5325af044083 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -22,6 +22,7 @@ import android.content.Context;  import android.content.Intent;  import android.graphics.Bitmap;  import android.net.Uri; +import android.os.Bundle;  import android.os.Parcel;  import android.os.Parcelable;  import android.text.TextUtils; @@ -30,6 +31,7 @@ import android.widget.ProgressBar;  import android.widget.RemoteViews;  import java.text.NumberFormat; +import java.util.ArrayList;  /**   * A class that represents how a persistent notification is to be presented to @@ -51,36 +53,58 @@ public class Notification implements Parcelable       * Use all default values (where applicable).       */      public static final int DEFAULT_ALL = ~0; -     +      /**       * Use the default notification sound. This will ignore any given       * {@link #sound}. -     *  +     * +       * @see #defaults -     */  +     */ +      public static final int DEFAULT_SOUND = 1;      /**       * Use the default notification vibrate. This will ignore any given -     * {@link #vibrate}. Using phone vibration requires the  +     * {@link #vibrate}. Using phone vibration requires the       * {@link android.Manifest.permission#VIBRATE VIBRATE} permission. -     *  +     *       * @see #defaults -     */  +     */ +      public static final int DEFAULT_VIBRATE = 2; -     +      /**       * Use the default notification lights. This will ignore the       * {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or       * {@link #ledOnMS}. -     *  +     *       * @see #defaults -     */  +     */ +      public static final int DEFAULT_LIGHTS = 4; -     +      /** -     * The timestamp for the notification.  The icons and expanded views -     * are sorted by this key. +     * A timestamp related to this notification, in milliseconds since the epoch. +     *  +     * Default value: {@link System#currentTimeMillis() Now}. +     * +     * Choose a timestamp that will be most relevant to the user. For most finite events, this +     * corresponds to the time the event happened (or will happen, in the case of events that have +     * yet to occur but about which the user is being informed). Indefinite events should be +     * timestamped according to when the activity began.  +     *  +     * Some examples: +     *  +     * <ul> +     *   <li>Notification of a new chat message should be stamped when the message was received.</li> +     *   <li>Notification of an ongoing file download (with a progress bar, for example) should be stamped when the download started.</li> +     *   <li>Notification of a completed file download should be stamped when the download finished.</li> +     *   <li>Notification of an upcoming meeting should be stamped with the time the meeting will begin (that is, in the future).</li> +     *   <li>Notification of an ongoing stopwatch (increasing timer) should be stamped with the watch's start time. +     *   <li>Notification of an ongoing countdown timer should be stamped with the timer's end time. +     * </ul>  +     *        */      public long when; @@ -100,10 +124,16 @@ public class Notification implements Parcelable      public int iconLevel;      /** -     * The number of events that this notification represents.  For example, in a new mail -     * notification, this could be the number of unread messages.  This number is superimposed over -     * the icon in the status bar.  If the number is 0 or negative, it is not shown in the status -     * bar. +     * The number of events that this notification represents. For example, in a new mail +     * notification, this could be the number of unread messages. +     *  +     * The system may or may not use this field to modify the appearance of the notification. For +     * example, before {@link android.os.Build.VERSION_CODES#HONEYCOMB}, this number was +     * superimposed over the icon in the status bar. Starting with +     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, the template used by +     * {@link Notification.Builder} has displayed the number in the expanded notification view. +     *  +     * If the number is 0 or negative, it is never shown.       */      public int number; @@ -121,10 +151,11 @@ public class Notification implements Parcelable      public PendingIntent contentIntent;      /** -     * The intent to execute when the status entry is deleted by the user -     * with the "Clear All Notifications" button. This probably shouldn't -     * be launching an activity since several of those will be sent at the -     * same time. +     * The intent to execute when the notification is explicitly dismissed by the user, either with +     * the "Clear All" button or by swiping it away individually. +     * +     * This probably shouldn't be launching an activity since several of those will be sent +     * at the same time.       */      public PendingIntent deleteIntent; @@ -139,11 +170,6 @@ public class Notification implements Parcelable       * Text to scroll across the screen when this item is added to       * the status bar on large and smaller devices.       * -     * <p>This field is provided separately from the other ticker fields -     * both for compatibility and to allow an application to choose different -     * text for when the text scrolls in and when it is displayed all at once -     * in conjunction with one or more icons. -     *       * @see #tickerView       */      public CharSequence tickerText; @@ -166,9 +192,9 @@ public class Notification implements Parcelable      /**       * The sound to play. -     *  +     *       * <p> -     * To play the default notification sound, see {@link #defaults}.  +     * To play the default notification sound, see {@link #defaults}.       * </p>       */      public Uri sound; @@ -187,14 +213,13 @@ public class Notification implements Parcelable       */      public int audioStreamType = STREAM_DEFAULT; -          /** -     * The pattern with which to vibrate.  -     *  +     * The pattern with which to vibrate. +     *       * <p>       * To vibrate the default pattern, see {@link #defaults}.       * </p> -     *  +     *       * @see android.os.Vibrator#vibrate(long[],int)       */      public long[] vibrate; @@ -235,7 +260,6 @@ public class Notification implements Parcelable       */      public int defaults; -      /**       * Bit to be bitwise-ored into the {@link #flags} field that should be       * set if you want the LED on for this notification. @@ -252,7 +276,7 @@ public class Notification implements Parcelable       * because they will be set to values that work on any given hardware.       * <p>       * The alpha channel must be set for forward compatibility. -     *  +     *       */      public static final int FLAG_SHOW_LIGHTS        = 0x00000001; @@ -282,7 +306,8 @@ public class Notification implements Parcelable      /**       * Bit to be bitwise-ored into the {@link #flags} field that should be       * set if the notification should be canceled when it is clicked by the -     * user.  On tablets, the  +     * user.  On tablets, the +       */      public static final int FLAG_AUTO_CANCEL        = 0x00000010; @@ -301,22 +326,105 @@ public class Notification implements Parcelable      public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;      /** -     * Bit to be bitwise-ored into the {@link #flags} field that should be set if this notification -     * represents a high-priority event that may be shown to the user even if notifications are -     * otherwise unavailable (that is, when the status bar is hidden). This flag is ideally used -     * in conjunction with {@link #fullScreenIntent}. +     * Obsolete flag indicating high-priority notifications; use the priority field instead. +     *  +     * @deprecated Use {@link #priority} with a positive value.       */ -    public static final int FLAG_HIGH_PRIORITY = 0x00000080; +    public static final int FLAG_HIGH_PRIORITY      = 0x00000080;      public int flags;      /** -     * Constructs a Notification object with everything set to 0. +     * Default notification {@link #priority}. If your application does not prioritize its own +     * notifications, use this value for all notifications. +     */ +    public static final int PRIORITY_DEFAULT = 0; + +    /** +     * Lower {@link #priority}, for items that are less important. The UI may choose to show these +     * items smaller, or at a different position in the list, compared with your app's +     * {@link #PRIORITY_DEFAULT} items. +     */ +    public static final int PRIORITY_LOW = -1; + +    /** +     * Lowest {@link #priority}; these items might not be shown to the user except under special +     * circumstances, such as detailed notification logs. +     */ +    public static final int PRIORITY_MIN = -2; + +    /** +     * Higher {@link #priority}, for more important notifications or alerts. The UI may choose to +     * show these items larger, or at a different position in notification lists, compared with +     * your app's {@link #PRIORITY_DEFAULT} items. +     */ +    public static final int PRIORITY_HIGH = 1; + +    /** +     * Highest {@link #priority}, for your application's most important items that require the +     * user's prompt attention or input. +     */ +    public static final int PRIORITY_MAX = 2; + +    /** +     * Relative priority for this notification. +     *  +     * Priority is an indication of how much of the user's valuable attention should be consumed by +     * this notification. Low-priority notifications may be hidden from the user in certain +     * situations, while the user might be interrupted for a higher-priority notification. The +     * system will make a determination about how to interpret notification priority as described in  +     * MUMBLE MUMBLE. +     */ +    public int priority; +     +    /** +     * Notification type: incoming call (voice or video) or similar synchronous communication request. +     */ +    public static final String KIND_CALL = "android.call"; + +    /** +     * Notification type: incoming direct message (SMS, instant message, etc.). +     */ +    public static final String KIND_MESSAGE = "android.message"; + +    /** +     * Notification type: asynchronous bulk message (email). +     */ +    public static final String KIND_EMAIL = "android.email"; + +    /** +     * Notification type: calendar event. +     */ +    public static final String KIND_EVENT = "android.event"; + +    /** +     * Notification type: promotion or advertisement. +     */ +    public static final String KIND_PROMO = "android.promo"; + +    /** +     * If this notification matches of one or more special types (see the <code>KIND_*</code> +     * constants), add them here, best match first. +     */ +    public String[] kind; + +    /** +     * Extra key for people values (type TBD). +     * +     * @hide +     */ +    public static final String EXTRA_PEOPLE = "android.people"; + +    private Bundle extras; + +    /** +     * Constructs a Notification object with default values.       * You might want to consider using {@link Builder} instead.       */      public Notification()      {          this.when = System.currentTimeMillis(); +        this.priority = PRIORITY_DEFAULT;      }      /** @@ -396,6 +504,14 @@ public class Notification implements Parcelable          if (parcel.readInt() != 0) {              fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);          } + +        priority = parcel.readInt(); +         +        kind = parcel.createStringArray(); // may set kind to null + +        if (parcel.readInt() != 0) { +            extras = parcel.readBundle(); +        }      }      @Override @@ -438,9 +554,23 @@ public class Notification implements Parcelable          that.ledOnMS = this.ledOnMS;          that.ledOffMS = this.ledOffMS;          that.defaults = this.defaults; -         +          that.flags = this.flags; +        that.priority = this.priority; +         +        final String[] thiskind = this.kind; +        if (thiskind != null) { +            final int N = thiskind.length; +            final String[] thatkind = that.kind = new String[N]; +            System.arraycopy(thiskind, 0, thatkind, 0, N); +        } + +        if (this.extras != null) { +            that.extras = new Bundle(this.extras); + +        } +          return that;      } @@ -517,6 +647,17 @@ public class Notification implements Parcelable          } else {              parcel.writeInt(0);          } + +        parcel.writeInt(priority); +         +        parcel.writeStringArray(kind); // ok for null +         +        if (extras != null) { +            parcel.writeInt(1); +            extras.writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        }      }      /** @@ -551,7 +692,7 @@ public class Notification implements Parcelable       * that you take care of task management as described in the       * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back       * Stack</a> document. -     *  +     *       * @deprecated Use {@link Builder} instead.       */      @Deprecated @@ -579,7 +720,9 @@ public class Notification implements Parcelable      @Override      public String toString() {          StringBuilder sb = new StringBuilder(); -        sb.append("Notification(contentView="); +        sb.append("Notification(pri="); +        sb.append(priority); +        sb.append(" contentView=");          if (contentView != null) {              sb.append(contentView.getPackage());              sb.append("/0x"); @@ -587,6 +730,7 @@ public class Notification implements Parcelable          } else {              sb.append("null");          } +        // TODO(dsandler): defaults take precedence over local values, so reorder the branches below          sb.append(" vibrate=");          if (this.vibrate != null) {              int N = this.vibrate.length-1; @@ -604,7 +748,7 @@ public class Notification implements Parcelable          } else {              sb.append("null");          } -        sb.append(",sound="); +        sb.append(" sound=");          if (this.sound != null) {              sb.append(this.sound.toString());          } else if ((this.defaults & DEFAULT_SOUND) != 0) { @@ -612,20 +756,39 @@ public class Notification implements Parcelable          } else {              sb.append("null");          } -        sb.append(",defaults=0x"); +        sb.append(" defaults=0x");          sb.append(Integer.toHexString(this.defaults)); -        sb.append(",flags=0x"); +        sb.append(" flags=0x");          sb.append(Integer.toHexString(this.flags)); -        if ((this.flags & FLAG_HIGH_PRIORITY) != 0) { -            sb.append("!!!1!one!"); +        sb.append(" kind=["); +        if (this.kind == null) { +            sb.append("null"); +        } else { +            for (int i=0; i<this.kind.length; i++) { +                if (i>0) sb.append(","); +                sb.append(this.kind[i]); +            }          } -        sb.append(")"); +        sb.append("])");          return sb.toString();      }      /** -     * Builder class for {@link Notification} objects.  Allows easier control over -     * all the flags, as well as help constructing the typical notification layouts. +     * Builder class for {@link Notification} objects. +     *  +     * Provides a convenient way to set the various fields of a {@link Notification} and generate +     * content views using the platform's notification layout template.  +     *  +     * Example: +     *  +     * <pre class="prettyprint"> +     * Notification noti = new Notification.Builder() +     *         .setContentTitle("New mail from " + sender.toString()) +     *         .setContentText(subject) +     *         .setSmallIcon(R.drawable.new_mail) +     *         .setLargeIcon(aBitmap) +     *         .getNotification(); +     * </pre>       */      public static class Builder {          private Context mContext; @@ -655,16 +818,28 @@ public class Notification implements Parcelable          private int mProgressMax;          private int mProgress;          private boolean mProgressIndeterminate; +        private ArrayList<String> mKindList = new ArrayList<String>(1); +        private Bundle mExtras; +        private int mPriority;          /** -         * Constructor. +         * Constructs a new Builder with the defaults:           * -         * Automatically sets the when field to {@link System#currentTimeMillis() -         * System.currentTimeMllis()} and the audio stream to the {@link #STREAM_DEFAULT}. + +         * <table> +         * <tr><th align=right>priority</th> +         *     <td>{@link #PRIORITY_DEFAULT}</td></tr> +         * <tr><th align=right>when</th> +         *     <td>now ({@link System#currentTimeMillis()})</td></tr> +         * <tr><th align=right>audio stream</th> +         *     <td>{@link #STREAM_DEFAULT}</td></tr> +         * </table>           * -         * @param context A {@link Context} that will be used to construct the -         *      RemoteViews. The Context will not be held past the lifetime of this -         *      Builder object. + +         * @param context +         *            A {@link Context} that will be used by the Builder to construct the +         *            RemoteViews. The Context will not be held past the lifetime of this Builder +         *            object.           */          public Builder(Context context) {              mContext = context; @@ -672,11 +847,14 @@ public class Notification implements Parcelable              // Set defaults to match the defaults of a Notification              mWhen = System.currentTimeMillis();              mAudioStreamType = STREAM_DEFAULT; +            mPriority = PRIORITY_DEFAULT;          }          /** -         * Set the time that the event occurred.  Notifications in the panel are -         * sorted by this time. +         * Add a timestamp pertaining to the notification (usually the time the event occurred). +         * + +         * @see Notification#when           */          public Builder setWhen(long when) {              mWhen = when; @@ -684,11 +862,18 @@ public class Notification implements Parcelable          }          /** -         * Set the small icon to use in the notification layouts.  Different classes of devices -         * may return different sizes.  See the UX guidelines for more information on how to -         * design these icons. +         * Set the small icon resource, which will be used to represent the notification in the +         * status bar.           * -         * @param icon A resource ID in the application's package of the drawble to use. + +         * The platform template for the expanded view will draw this icon in the left, unless a +         * {@link #setLargeIcon(Bitmap) large icon} has also been specified, in which case the small +         * icon will be moved to the right-hand side. +         * + +         * @param icon +         *            A resource ID in the application's package of the drawable to use. +         * @see Notification#icon           */          public Builder setSmallIcon(int icon) {              mSmallIcon = icon; @@ -700,10 +885,11 @@ public class Notification implements Parcelable           * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable           * LevelListDrawable}.           * -         * @param icon A resource ID in the application's package of the drawble to use. +         * @param icon A resource ID in the application's package of the drawable to use.           * @param level The level to use for the icon.           * -         * @see android.graphics.drawable.LevelListDrawable +         * @see Notification#icon +         * @see Notification#iconLevel           */          public Builder setSmallIcon(int icon, int level) {              mSmallIcon = icon; @@ -712,7 +898,7 @@ public class Notification implements Parcelable          }          /** -         * Set the title (first row) of the notification, in a standard notification. +         * Set the first line of text in the platform notification template.           */          public Builder setContentTitle(CharSequence title) {              mContentTitle = title; @@ -720,7 +906,7 @@ public class Notification implements Parcelable          }          /** -         * Set the text (second row) of the notification, in a standard notification. +         * Set the second line of text in the platform notification template.           */          public Builder setContentText(CharSequence text) {              mContentText = text; @@ -738,7 +924,11 @@ public class Notification implements Parcelable          }          /** -         * Set the large text at the right-hand side of the notification. +         * A small piece of additional information pertaining to this notification. +         * + +         * The platform template will draw this on the last line of the notification, at the far +         * right (to the right of a smallIcon if it has been placed there).           */          public Builder setContentInfo(CharSequence info) {              mContentInfo = info; @@ -746,8 +936,10 @@ public class Notification implements Parcelable          }          /** -         * Set the progress this notification represents, which may be -         * represented as a {@link ProgressBar}. +         * Set the progress this notification represents. +         * + +         * The platform template will represent this using a {@link ProgressBar}.           */          public Builder setProgress(int max, int progress, boolean indeterminate) {              mProgressMax = max; @@ -757,7 +949,10 @@ public class Notification implements Parcelable          }          /** -         * Supply a custom RemoteViews to use instead of the standard one. +         * Supply a custom RemoteViews to use instead of the platform template. +         * + +         * @see Notification#contentView           */          public Builder setContent(RemoteViews views) {              mContentView = views; @@ -765,12 +960,20 @@ public class Notification implements Parcelable          }          /** -         * Supply a {@link PendingIntent} to send when the notification is clicked. -         * If you do not supply an intent, you can now add PendingIntents to individual -         * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent -         * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}.  Be sure to -         * read {@link Notification#contentIntent Notification.contentIntent} for -         * how to correctly use this. +         * Supply a {@link PendingIntent} to be sent when the notification is clicked. +         * + +         * As of {@link android.os.Build.VERSION_CODES#HONEYCOMB}, if this field is unset and you +         * have specified a custom RemoteViews with {@link #setContent(RemoteViews)}, you can use +         * {@link RemoteViews#setOnClickPendingIntent RemoteViews.setOnClickPendingIntent(int,PendingIntent)} + +         * to assign PendingIntents to individual views in that custom layout (i.e., to create + +         * clickable buttons inside the +         * notification view). +         * + +         * @see Notification#contentIntent Notification.contentIntent           */          public Builder setContentIntent(PendingIntent intent) {              mContentIntent = intent; @@ -778,11 +981,10 @@ public class Notification implements Parcelable          }          /** -         * Supply a {@link PendingIntent} to send when the notification is cleared by the user -         * directly from the notification panel.  For example, this intent is sent when the user -         * clicks the "Clear all" button, or the individual "X" buttons on notifications.  This -         * intent is not sent when the application calls {@link NotificationManager#cancel -         * NotificationManager.cancel(int)}. +         * Supply a {@link PendingIntent} to send when the notification is cleared explicitly by the user. +         * + +         * @see Notification#deleteIntent           */          public Builder setDeleteIntent(PendingIntent intent) {              mDeleteIntent = intent; @@ -801,6 +1003,8 @@ public class Notification implements Parcelable           * @param intent The pending intent to launch.           * @param highPriority Passing true will cause this notification to be sent           *          even if other notifications are suppressed. +         * +         * @see Notification#fullScreenIntent           */          public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {              mFullScreenIntent = intent; @@ -809,8 +1013,11 @@ public class Notification implements Parcelable          }          /** -         * Set the text that is displayed in the status bar when the notification first +         * Set the "ticker" text which is displayed in the status bar when the notification first           * arrives. +         * + +         * @see Notification#tickerText           */          public Builder setTicker(CharSequence tickerText) {              mTickerText = tickerText; @@ -821,6 +1028,9 @@ public class Notification implements Parcelable           * Set the text that is displayed in the status bar when the notification first           * arrives, and also a RemoteViews object that may be displayed instead on some           * devices. +         * +         * @see Notification#tickerText +         * @see Notification#tickerView           */          public Builder setTicker(CharSequence tickerText, RemoteViews views) {              mTickerText = tickerText; @@ -829,7 +1039,12 @@ public class Notification implements Parcelable          }          /** -         * Set the large icon that is shown in the ticker and notification. +         * Add a large icon to the notification (and the ticker on some devices). +         * +         * In the platform template, this image will be shown on the left of the notification view +         * in place of the {@link #setSmallIcon(int) small icon} (which will move to the right side). +         * +         * @see Notification#largeIcon           */          public Builder setLargeIcon(Bitmap icon) {              mLargeIcon = icon; @@ -837,7 +1052,11 @@ public class Notification implements Parcelable          }          /** -         * Set the sound to play.  It will play on the default stream. +         * Set the sound to play. +         * +         * It will be played on the {@link #STREAM_DEFAULT default stream} for notifications. +         * +         * @see Notification#sound           */          public Builder setSound(Uri sound) {              mSound = sound; @@ -846,10 +1065,11 @@ public class Notification implements Parcelable          }          /** -         * Set the sound to play.  It will play on the stream you supply. +         * Set the sound to play, along with a specific stream on which to play it.           * -         * @see #STREAM_DEFAULT -         * @see AudioManager for the <code>STREAM_</code> constants. +         * See {@link android.media.AudioManager} for the <code>STREAM_</code> constants. +         * +         * @see Notification#sound           */          public Builder setSound(Uri sound, int streamType) {              mSound = sound; @@ -860,8 +1080,12 @@ public class Notification implements Parcelable          /**           * Set the vibration pattern to use.           * -         * @see android.os.Vibrator for a discussion of the <code>pattern</code> -         * parameter. + +         * See {@link android.os.Vibrator#vibrate(long[], int)} for a discussion of the +         * <code>pattern</code> parameter. +         * + +         * @see Notification#vibrate           */          public Builder setVibrate(long[] pattern) {              mVibrate = pattern; @@ -869,9 +1093,16 @@ public class Notification implements Parcelable          }          /** -         * Set the argb value that you would like the LED on the device to blnk, as well as the -         * rate.  The rate is specified in terms of the number of milliseconds to be on -         * and then the number of milliseconds to be off. +         * Set the desired color for the indicator LED on the device, as well as the +         * blink duty cycle (specified in milliseconds). +         * + +         * Not all devices will honor all (or even any) of these values. +         * + +         * @see Notification#ledARGB +         * @see Notification#ledOnMS +         * @see Notification#ledOffMS           */          public Builder setLights(int argb, int onMs, int offMs) {              mLedArgb = argb; @@ -881,15 +1112,20 @@ public class Notification implements Parcelable          }          /** -         * Set whether this is an ongoing notification. +         * Set whether this is an "ongoing" notification.           * -         * <p>Ongoing notifications differ from regular notifications in the following ways: -         * <ul> -         *   <li>Ongoing notifications are sorted above the regular notifications in the -         *   notification panel.</li> -         *   <li>Ongoing notifications do not have an 'X' close button, and are not affected -         *   by the "Clear all" button. -         * </ul> + +         * Ongoing notifications cannot be dismissed by the user, so your application or service +         * must take care of canceling them. +         * + +         * They are typically used to indicate a background task that the user is actively engaged +         * with (e.g., playing music) or is pending in some way and therefore occupying the device +         * (e.g., a file download, sync operation, active network connection). +         * + +         * @see Notification#FLAG_ONGOING_EVENT +         * @see Service#setForeground(boolean)           */          public Builder setOngoing(boolean ongoing) {              setFlag(FLAG_ONGOING_EVENT, ongoing); @@ -899,6 +1135,8 @@ public class Notification implements Parcelable          /**           * Set this flag if you would only like the sound, vibrate           * and ticker to be played if the notification is not already showing. +         * +         * @see Notification#FLAG_ONLY_ALERT_ONCE           */          public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {              setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce); @@ -906,10 +1144,10 @@ public class Notification implements Parcelable          }          /** -         * Setting this flag will make it so the notification is automatically -         * canceled when the user clicks it in the panel.  The PendingIntent -         * set with {@link #setDeleteIntent} will be broadcast when the notification -         * is canceled. +         * Make this notification automatically dismissed when the user touches it. The +         * PendingIntent set with {@link #setDeleteIntent} will be sent when this happens. +         * +         * @see Notification#FLAG_AUTO_CANCEL           */          public Builder setAutoCancel(boolean autoCancel) {              setFlag(FLAG_AUTO_CANCEL, autoCancel); @@ -917,7 +1155,7 @@ public class Notification implements Parcelable          }          /** -         * Set the default notification options that will be used. +         * Set which notification properties will be inherited from system defaults.           * <p>           * The value should be one or more of the following fields combined with           * bitwise-or: @@ -930,6 +1168,41 @@ public class Notification implements Parcelable              return this;          } +        /** +         * Set the priority of this notification. +         * +         * @see Notification#priority +         */ +        public Builder setPriority(int pri) { +            mPriority = pri; +            return this; +        } +         +        /** +         * Add a kind (category) to this notification. Optional. +         *  +         * @see Notification#kind +         */ +        public Builder addKind(String k) { +            mKindList.add(k); +            return this; +        } + +        /** +         * Add metadata to this notification. +         * +         * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's +         * current contents are copied into the Notification each time {@link #getNotification()} is +         * called. +         * +         * @see Notification#extras +         * @hide +         */ +        public Builder setExtras(Bundle bag) { +            mExtras = bag; +            return this; +        } +          private void setFlag(int mask, boolean value) {              if (value) {                  mFlags |= mask; @@ -1042,6 +1315,14 @@ public class Notification implements Parcelable              if ((mDefaults & DEFAULT_LIGHTS) != 0) {                  n.flags |= FLAG_SHOW_LIGHTS;              } +            if (mKindList.size() > 0) { +                n.kind = new String[mKindList.size()]; +                mKindList.toArray(n.kind); +            } else { +                n.kind = null; +            } +            n.priority = mPriority; +            n.extras = mExtras != null ? new Bundle(mExtras) : null;              return n;          }      } diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.java b/core/java/com/android/internal/statusbar/StatusBarNotification.java index c03ff1a15f88..d443523a2c12 100644 --- a/core/java/com/android/internal/statusbar/StatusBarNotification.java +++ b/core/java/com/android/internal/statusbar/StatusBarNotification.java @@ -34,25 +34,23 @@ if (truncatedTicker != null && truncatedTicker.length() > maxTickerLen) {  }  */ +/** + * Class encapsulating a Notification. Sent by the NotificationManagerService to the IStatusBar (in System UI). + */  public class StatusBarNotification implements Parcelable { -    public static int PRIORITY_JIFFY_EXPRESS = -100; -    public static int PRIORITY_NORMAL        = 0; -    public static int PRIORITY_ONGOING       = 100; -    public static int PRIORITY_SYSTEM        = 200; -      public String pkg;      public int id;      public String tag;      public int uid;      public int initialPid;      public Notification notification; -    public int priority = PRIORITY_NORMAL; - +    public int score; +          public StatusBarNotification() {      }      public StatusBarNotification(String pkg, int id, String tag, -            int uid, int initialPid, Notification notification) { +            int uid, int initialPid, int score, Notification notification) {          if (pkg == null) throw new NullPointerException();          if (notification == null) throw new NullPointerException(); @@ -61,9 +59,8 @@ public class StatusBarNotification implements Parcelable {          this.tag = tag;          this.uid = uid;          this.initialPid = initialPid; +        this.score = score;          this.notification = notification; - -        this.priority = PRIORITY_NORMAL;      }      public StatusBarNotification(Parcel in) { @@ -80,7 +77,7 @@ public class StatusBarNotification implements Parcelable {          }          this.uid = in.readInt();          this.initialPid = in.readInt(); -        this.priority = in.readInt(); +        this.score = in.readInt();          this.notification = new Notification(in);      } @@ -95,7 +92,7 @@ public class StatusBarNotification implements Parcelable {          }          out.writeInt(this.uid);          out.writeInt(this.initialPid); -        out.writeInt(this.priority); +        out.writeInt(this.score);          this.notification.writeToParcel(out, flags);      } @@ -119,12 +116,12 @@ public class StatusBarNotification implements Parcelable {      public StatusBarNotification clone() {          return new StatusBarNotification(this.pkg, this.id, this.tag, -                this.uid, this.initialPid, this.notification.clone()); +                this.uid, this.initialPid, this.score, this.notification.clone());      }      public String toString() { -        return "StatusBarNotification(package=" + pkg + " id=" + id + " tag=" + tag -                + " notification=" + notification + " priority=" + priority + ")"; +        return "StatusBarNotification(pkg=" + pkg + " id=" + id + " tag=" + tag +                + " score=" + score + " notn=" + notification + ")";      }      public boolean isOngoing() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index 3d904ee52bda..6fbcd64786c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -47,12 +47,13 @@ public class NotificationData {      }      private final ArrayList<Entry> mEntries = new ArrayList<Entry>();      private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() { +        // sort first by score, then by when          public int compare(Entry a, Entry b) {              final StatusBarNotification na = a.notification;              final StatusBarNotification nb = b.notification; -            int priDiff = na.priority - nb.priority; -            return (priDiff != 0) -                ? priDiff +            int d = na.score - nb.score; +            return (d != 0) +                ? d                  : (int)(na.notification.when - nb.notification.when);          }      }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 5a1e3f440edd..ad41155eee27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -232,6 +232,11 @@ public class PhoneStatusBar extends StatusBar {      private int mNavigationIconHints = 0; +    // TODO(dsandler): codify this stuff in NotificationManager's header somewhere +    private int mDisplayMinScore             = Notification.PRIORITY_LOW * 10; +    private int mIntruderMinScore            = Notification.PRIORITY_HIGH * 10; +    private int mIntruderInImmersiveMinScore = Notification.PRIORITY_HIGH * 10 + 5; +          private class ExpandedDialog extends Dialog {          ExpandedDialog(Context context) {              super(context, com.android.internal.R.style.Theme_Translucent_NoTitleBar); @@ -538,6 +543,7 @@ public class PhoneStatusBar extends StatusBar {      }      public void addNotification(IBinder key, StatusBarNotification notification) { +        /* if (DEBUG) */ Slog.d(TAG, "addNotification score=" + notification.score);          StatusBarIconView iconView = addNotificationViews(key, notification);          if (iconView == null) return; @@ -549,31 +555,30 @@ public class PhoneStatusBar extends StatusBar {              }          } catch (RemoteException ex) {          } -        if (immersive) { -            if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) { -                Slog.d(TAG, "Presenting high-priority notification in immersive activity"); -                // special new transient ticker mode -                // 1. Populate mIntruderAlertView - -                ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon); -                TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText); -                alertIcon.setImageDrawable(StatusBarIconView.getIcon( -                    alertIcon.getContext(), -                    iconView.getStatusBarIcon())); -                alertText.setText(notification.notification.tickerText); - -                View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content); -                button.setOnClickListener( -                    new NotificationClicker(notification.notification.contentIntent, -                        notification.pkg, notification.tag, notification.id)); - -                // 2. Animate mIntruderAlertView in -                mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER); - -                // 3. Set alarm to age the notification off (TODO) -                mHandler.removeMessages(MSG_HIDE_INTRUDER); -                mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS); -            } +        if ((notification.score >= mIntruderInImmersiveMinScore)  +                || (!immersive && (notification.score > mIntruderMinScore))) { +            Slog.d(TAG, "Presenting high-priority notification"); +            // special new transient ticker mode +            // 1. Populate mIntruderAlertView + +            ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon); +            TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText); +            alertIcon.setImageDrawable(StatusBarIconView.getIcon( +                alertIcon.getContext(), +                iconView.getStatusBarIcon())); +            alertText.setText(notification.notification.tickerText); + +            View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content); +            button.setOnClickListener( +                new NotificationClicker(notification.notification.contentIntent, +                    notification.pkg, notification.tag, notification.id)); + +            // 2. Animate mIntruderAlertView in +            mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER); + +            // 3. Set alarm to age the notification off (TODO) +            mHandler.removeMessages(MSG_HIDE_INTRUDER); +            mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);          } else if (notification.notification.fullScreenIntent != null) {              // not immersive & a full-screen alert should be shown              Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); @@ -630,8 +635,8 @@ public class PhoneStatusBar extends StatusBar {                  && oldContentView.getLayoutId() == contentView.getLayoutId();          ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();          boolean orderUnchanged = notification.notification.when==oldNotification.notification.when -                && notification.priority == oldNotification.priority; -                // priority now encompasses isOngoing() +                && notification.score == oldNotification.score; +                // score now encompasses/supersedes isOngoing()          boolean updateTicker = notification.notification.tickerText != null                  && !TextUtils.equals(notification.notification.tickerText, @@ -723,69 +728,6 @@ public class PhoneStatusBar extends StatusBar {      } -    View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) { -        Notification n = notification.notification; -        RemoteViews remoteViews = n.contentView; -        if (remoteViews == null) { -            return null; -        } - -        // create the row view -        LayoutInflater inflater = (LayoutInflater)mContext.getSystemService( -                Context.LAYOUT_INFLATER_SERVICE); -        View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false); - -        // wire up the veto button -        View vetoButton = updateNotificationVetoButton(row, notification); -        vetoButton.setContentDescription(mContext.getString( -                R.string.accessibility_remove_notification)); - -        // the large icon -        ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon); -        if (notification.notification.largeIcon != null) { -            largeIcon.setImageBitmap(notification.notification.largeIcon); -        } else { -            largeIcon.getLayoutParams().width = 0; -            largeIcon.setVisibility(View.INVISIBLE); -        } - -        // bind the click event to the content area -        ViewGroup content = (ViewGroup)row.findViewById(R.id.content); -        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); -        content.setOnFocusChangeListener(mFocusChangeListener); -        PendingIntent contentIntent = n.contentIntent; -        if (contentIntent != null) { -            final View.OnClickListener listener = new NotificationClicker(contentIntent, -                    notification.pkg, notification.tag, notification.id); -            largeIcon.setOnClickListener(listener); -            content.setOnClickListener(listener); -        } else { -            largeIcon.setOnClickListener(null); -            content.setOnClickListener(null); -        } - -        View expanded = null; -        Exception exception = null; -        try { -            expanded = remoteViews.apply(mContext, content); -        } -        catch (RuntimeException e) { -            exception = e; -        } -        if (expanded == null) { -            String ident = notification.pkg + "/0x" + Integer.toHexString(notification.id); -            Slog.e(TAG, "couldn't inflate view for notification " + ident, exception); -            return null; -        } else { -            content.addView(expanded); -            row.setDrawingCacheEnabled(true); -        } - -        applyLegacyRowBackground(notification, content); - -        return new View[] { row, content, expanded }; -    } -      StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {          if (DEBUG) {              Slog.d(TAG, "addNotificationViews(key=" + key + ", notification=" + notification); @@ -848,7 +790,7 @@ public class PhoneStatusBar extends StatusBar {          for (int i=0; i<toShow.size(); i++) {              View v = toShow.get(i);              if (v.getParent() == null) { -                mPile.addView(v, 0); // the notification shade has newest at the top +                mPile.addView(v, i);              }          }      } @@ -1805,7 +1747,7 @@ public class PhoneStatusBar extends StatusBar {                      NotificationData.Entry e = mNotificationData.get(i);                      pw.println("    [" + i + "] key=" + e.key + " icon=" + e.icon);                      StatusBarNotification n = e.notification; -                    pw.println("         pkg=" + n.pkg + " id=" + n.id + " priority=" + n.priority); +                    pw.println("         pkg=" + n.pkg + " id=" + n.id + " score=" + n.score);                      pw.println("         notification=" + n.notification);                      pw.println("         tickerText=\"" + n.notification.tickerText + "\"");                  } @@ -2315,6 +2257,30 @@ public class PhoneStatusBar extends StatusBar {          vib.vibrate(250);      } +    public int getScoreThreshold() { +        return mDisplayMinScore; +    } + +    public void setScoreThreshold(int score) { +        // XXX HAX +        if (mDisplayMinScore != score) { +            this.mDisplayMinScore = score; +            applyScoreThreshold(); +        } +    } +     +    private void applyScoreThreshold() { +        int N = mNotificationData.size(); +        for (int i=0; i<N; i++) { +            NotificationData.Entry entry = mNotificationData.get(i); +            int vis = (entry.notification.score < mDisplayMinScore) +                ? View.GONE +                : View.VISIBLE; +            entry.row.setVisibility(vis); +            entry.icon.setVisibility(vis); +        } +    } +      Runnable mStartTracing = new Runnable() {          public void run() {              vibrate(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java index bb326fef461f..a60bba7ce106 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java @@ -99,13 +99,14 @@ public class LocationController extends BroadcastReceiver {                  // Notification.Builder will helpfully fill these out for you no matter what you do                  n.tickerView = null;                  n.tickerText = null; +                 +                n.priority = Notification.PRIORITY_HIGH;                  int[] idOut = new int[1]; -                mNotificationService.enqueueNotificationWithTagPriority( +                mNotificationService.enqueueNotificationWithTag(                          mContext.getPackageName(),                          null,                           GPS_NOTIFICATION_ID,  -                        StatusBarNotification.PRIORITY_SYSTEM, // !!!1!one!!!                          n,                          idOut);              } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 62874087de59..288c0403feea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -860,8 +860,8 @@ public class TabletStatusBar extends StatusBar implements                  && oldContentView.getLayoutId() == contentView.getLayoutId();          ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();          boolean orderUnchanged = notification.notification.when==oldNotification.notification.when -                && notification.priority == oldNotification.priority; -                // priority now encompasses isOngoing() +                && notification.score == oldNotification.score; +                // score now encompasses/supersedes isOngoing()          boolean updateTicker = notification.notification.tickerText != null                  && !TextUtils.equals(notification.notification.tickerText,                          oldEntry.notification.notification.tickerText); @@ -1689,7 +1689,7 @@ public class TabletStatusBar extends StatusBar implements                  mNotificationDNDDummyEntry = new NotificationData.Entry(                          null, -                        new StatusBarNotification("", 0, "", 0, 0, dndNotification), +                        new StatusBarNotification("", 0, "", 0, 0, Notification.PRIORITY_MAX, dndNotification),                          iconView);                  mIconLayout.addView(iconView, params); diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 34a8a027673e..c83471e8831b 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -146,19 +146,18 @@ public class NotificationManagerService extends INotificationManager.Stub          final int id;          final int uid;          final int initialPid; -        final int priority;          final Notification notification; +        final int score;          IBinder statusBarKey; -        NotificationRecord(String pkg, String tag, int id, int uid, int initialPid, int priority, -                Notification notification) +        NotificationRecord(String pkg, String tag, int id, int uid, int initialPid, int score, Notification notification)          {              this.pkg = pkg;              this.tag = tag;              this.id = id;              this.uid = uid;              this.initialPid = initialPid; -            this.priority = priority; +            this.score = score;              this.notification = notification;          } @@ -166,6 +165,8 @@ public class NotificationManagerService extends INotificationManager.Stub              pw.println(prefix + this);              pw.println(prefix + "  icon=0x" + Integer.toHexString(notification.icon)                      + " / " + idDebugString(baseContext, this.pkg, notification.icon)); +            pw.println(prefix + "  pri=" + notification.priority); +            pw.println(prefix + "  score=" + this.score);              pw.println(prefix + "  contentIntent=" + notification.contentIntent);              pw.println(prefix + "  deleteIntent=" + notification.deleteIntent);              pw.println(prefix + "  tickerText=" + notification.tickerText); @@ -187,7 +188,7 @@ public class NotificationManagerService extends INotificationManager.Stub                  + " pkg=" + pkg                  + " id=" + Integer.toHexString(id)                  + " tag=" + tag  -                + " pri=" + priority  +                + " score=" + score                  + "}";          }      } @@ -660,28 +661,17 @@ public class NotificationManagerService extends INotificationManager.Stub          enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),                  tag, id, notification, idOut);      } - -    public void enqueueNotificationWithTagPriority(String pkg, String tag, int id, int priority, -            Notification notification, int[] idOut) -    { -        enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(), -                tag, id, priority, notification, idOut); +     +    private final static int clamp(int x, int low, int high) { +        return (x < low) ? low : ((x > high) ? high : x);      } +          // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the      // uid/pid of another application)      public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,              String tag, int id, Notification notification, int[] idOut)      { -        enqueueNotificationInternal(pkg, callingUid, callingPid, tag, id,  -                ((notification.flags & Notification.FLAG_ONGOING_EVENT) != 0) -                    ? StatusBarNotification.PRIORITY_ONGOING -                    : StatusBarNotification.PRIORITY_NORMAL, -                notification, idOut); -    } -    public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid, -            String tag, int id, int priority, Notification notification, int[] idOut) -    {          checkIncomingCall(pkg);          // Limit the number of notifications that any given package except the android @@ -723,10 +713,35 @@ public class NotificationManagerService extends INotificationManager.Stub              }          } +        // === Scoring === +         +        // 0. Sanitize inputs +        notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, Notification.PRIORITY_MAX); +        // Migrate notification flags to scores +        if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) { +            if (notification.priority < Notification.PRIORITY_MAX) notification.priority = Notification.PRIORITY_MAX; +        } else if (0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) { +            if (notification.priority < Notification.PRIORITY_HIGH) notification.priority = Notification.PRIORITY_HIGH; +        } +         +        // 1. initial score: buckets of 10, around the app  +        int score = notification.priority * 10; //[-20..20] + +        // 2. Consult oracles (external heuristics) +        // TODO(dsandler): oracles + +        // 3. Apply local heuristics & overrides + +        // blocked apps +        // TODO(dsandler): add block db +        if (pkg.startsWith("com.test.spammer.")) { +            score = -1000; +        } +          synchronized (mNotificationList) {              NotificationRecord r = new NotificationRecord(pkg, tag, id,                       callingUid, callingPid,  -                    priority, +                    score,                      notification);              NotificationRecord old = null; @@ -752,9 +767,7 @@ public class NotificationManagerService extends INotificationManager.Stub              if (notification.icon != 0) {                  StatusBarNotification n = new StatusBarNotification(pkg, id, tag, -                        r.uid, r.initialPid, notification); -                n.priority = r.priority; - +                        r.uid, r.initialPid, score, notification);                  if (old != null && old.statusBarKey != null) {                      r.statusBarKey = old.statusBarKey;                      long identity = Binder.clearCallingIdentity(); diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java index f463a194070e..ae01c750847f 100644 --- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java +++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java @@ -765,22 +765,70 @@ public class NotificationTestList extends TestActivity              }          }, -        new Test("System priority notification") { +        new Test("PRIORITY_HIGH") {              public void run() {                  Notification n = new Notification.Builder(NotificationTestList.this) -                    .setSmallIcon(R.drawable.notification1) -                    .setContentTitle("System priority") +                    .setSmallIcon(R.drawable.notification5) +                    .setContentTitle("High priority")                      .setContentText("This should appear before all others") +                    .setPriority(Notification.PRIORITY_HIGH)                      .getNotification();                  int[] idOut = new int[1];                  try {                      INotificationManager directLine = mNM.getService(); -                    directLine.enqueueNotificationWithTagPriority( +                    directLine.enqueueNotificationWithTag( +                            getPackageName(), +                            null,  +                            100,  +                            n, +                            idOut); +                } catch (android.os.RemoteException ex) { +                    // oh well +                } +            } +        }, + +        new Test("PRIORITY_MAX") { +            public void run() { +                Notification n = new Notification.Builder(NotificationTestList.this) +                    .setSmallIcon(R.drawable.notification9) +                    .setContentTitle("MAX priority") +                    .setContentText("This might appear as an intruder alert") +                    .setPriority(Notification.PRIORITY_MAX) +                    .getNotification(); + +                int[] idOut = new int[1]; +                try { +                    INotificationManager directLine = mNM.getService(); +                    directLine.enqueueNotificationWithTag( +                            getPackageName(), +                            null,  +                            200,  +                            n, +                            idOut); +                } catch (android.os.RemoteException ex) { +                    // oh well +                } +            } +        }, + +        new Test("PRIORITY_MIN") { +            public void run() { +                Notification n = new Notification.Builder(NotificationTestList.this) +                    .setSmallIcon(R.drawable.notification0) +                    .setContentTitle("MIN priority") +                    .setContentText("You should not see this") +                    .setPriority(Notification.PRIORITY_MIN) +                    .getNotification(); + +                int[] idOut = new int[1]; +                try { +                    INotificationManager directLine = mNM.getService(); +                    directLine.enqueueNotificationWithTag(                              getPackageName(),                              null,                               1,  -                            StatusBarNotification.PRIORITY_SYSTEM,                              n,                              idOut);                  } catch (android.os.RemoteException ex) {  |