New notification priority and related APIs.
This change introduces a few new bits of data on Notification that will help the Notification Manager and System UI route and display them more intelligently: -> priority: an integer in a predefined range that indicates the app's best guess as to the relative importance (to the user, right now) of that information -> kind: a tag (really, set of tags) indicating the general type of notification (realtime, asynchronous, etc) -> extras: a Bundle of additional key/value pairs associated with this notification (currently @hidden) The notification manager takes these data into account when assigning to each notification a score which is passed with the notification on to the system UI, where it can be used to affect presentation. For example: - Spammy apps (identified explicitly by the user or by some other means) will have their notifications scored very negatively by the notification manager, allowing the UI to suppress them - Notifications of higher score might be shown larger or in a different way - Very important notifications (indicated by a very high score) might interrupt the user during an otherwise important task (videochat, game, etc) Implementation note: This replaces/extends the old internal notion of "priority", which was mostly used to organize ongoings and system notifications at the top of the panel. Change-Id: Ie063dc75f198a68e2b5734a3aa0cacb5aba1ac39
This commit is contained in:
@ -3626,12 +3626,22 @@ package android.app {
|
|||||||
field public static final int DEFAULT_VIBRATE = 2; // 0x2
|
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_AUTO_CANCEL = 16; // 0x10
|
||||||
field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
|
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_INSISTENT = 4; // 0x4
|
||||||
field public static final int FLAG_NO_CLEAR = 32; // 0x20
|
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_ONGOING_EVENT = 2; // 0x2
|
||||||
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
|
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 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 static final int STREAM_DEFAULT = -1; // 0xffffffff
|
||||||
field public int audioStreamType;
|
field public int audioStreamType;
|
||||||
field public android.app.PendingIntent contentIntent;
|
field public android.app.PendingIntent contentIntent;
|
||||||
@ -3642,11 +3652,13 @@ package android.app {
|
|||||||
field public android.app.PendingIntent fullScreenIntent;
|
field public android.app.PendingIntent fullScreenIntent;
|
||||||
field public int icon;
|
field public int icon;
|
||||||
field public int iconLevel;
|
field public int iconLevel;
|
||||||
|
field public java.lang.String[] kind;
|
||||||
field public android.graphics.Bitmap largeIcon;
|
field public android.graphics.Bitmap largeIcon;
|
||||||
field public int ledARGB;
|
field public int ledARGB;
|
||||||
field public int ledOffMS;
|
field public int ledOffMS;
|
||||||
field public int ledOnMS;
|
field public int ledOnMS;
|
||||||
field public int number;
|
field public int number;
|
||||||
|
field public int priority;
|
||||||
field public android.net.Uri sound;
|
field public android.net.Uri sound;
|
||||||
field public java.lang.CharSequence tickerText;
|
field public java.lang.CharSequence tickerText;
|
||||||
field public android.widget.RemoteViews tickerView;
|
field public android.widget.RemoteViews tickerView;
|
||||||
@ -3656,6 +3668,7 @@ package android.app {
|
|||||||
|
|
||||||
public static class Notification.Builder {
|
public static class Notification.Builder {
|
||||||
ctor public Notification.Builder(android.content.Context);
|
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 getNotification();
|
||||||
method public android.app.Notification.Builder setAutoCancel(boolean);
|
method public android.app.Notification.Builder setAutoCancel(boolean);
|
||||||
method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
|
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 setNumber(int);
|
||||||
method public android.app.Notification.Builder setOngoing(boolean);
|
method public android.app.Notification.Builder setOngoing(boolean);
|
||||||
method public android.app.Notification.Builder setOnlyAlertOnce(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 setProgress(int, int, boolean);
|
||||||
method public android.app.Notification.Builder setSmallIcon(int);
|
method public android.app.Notification.Builder setSmallIcon(int);
|
||||||
method public android.app.Notification.Builder setSmallIcon(int, int);
|
method public android.app.Notification.Builder setSmallIcon(int, int);
|
||||||
|
@ -33,7 +33,6 @@ interface INotificationManager
|
|||||||
void enqueueToast(String pkg, ITransientNotification callback, int duration);
|
void enqueueToast(String pkg, ITransientNotification callback, int duration);
|
||||||
void cancelToast(String pkg, ITransientNotification callback);
|
void cancelToast(String pkg, ITransientNotification callback);
|
||||||
void enqueueNotificationWithTag(String pkg, String tag, int id, in Notification notification, inout int[] idReceived);
|
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);
|
void cancelNotificationWithTag(String pkg, String tag, int id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@ -30,6 +31,7 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that represents how a persistent notification is to be presented to
|
* 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).
|
* Use all default values (where applicable).
|
||||||
*/
|
*/
|
||||||
public static final int DEFAULT_ALL = ~0;
|
public static final int DEFAULT_ALL = ~0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the default notification sound. This will ignore any given
|
* Use the default notification sound. This will ignore any given
|
||||||
* {@link #sound}.
|
* {@link #sound}.
|
||||||
*
|
*
|
||||||
|
|
||||||
* @see #defaults
|
* @see #defaults
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static final int DEFAULT_SOUND = 1;
|
public static final int DEFAULT_SOUND = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the default notification vibrate. This will ignore any given
|
* 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.
|
* {@link android.Manifest.permission#VIBRATE VIBRATE} permission.
|
||||||
*
|
*
|
||||||
* @see #defaults
|
* @see #defaults
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static final int DEFAULT_VIBRATE = 2;
|
public static final int DEFAULT_VIBRATE = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the default notification lights. This will ignore the
|
* Use the default notification lights. This will ignore the
|
||||||
* {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or
|
* {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or
|
||||||
* {@link #ledOnMS}.
|
* {@link #ledOnMS}.
|
||||||
*
|
*
|
||||||
* @see #defaults
|
* @see #defaults
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static final int DEFAULT_LIGHTS = 4;
|
public static final int DEFAULT_LIGHTS = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The timestamp for the notification. The icons and expanded views
|
* A timestamp related to this notification, in milliseconds since the epoch.
|
||||||
* are sorted by this key.
|
*
|
||||||
|
* 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;
|
public long when;
|
||||||
|
|
||||||
@ -100,10 +124,16 @@ public class Notification implements Parcelable
|
|||||||
public int iconLevel;
|
public int iconLevel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of events that this notification represents. For example, in a new mail
|
* 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
|
* notification, this could be the number of unread messages.
|
||||||
* the icon in the status bar. If the number is 0 or negative, it is not shown in the status
|
*
|
||||||
* bar.
|
* 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;
|
public int number;
|
||||||
|
|
||||||
@ -121,10 +151,11 @@ public class Notification implements Parcelable
|
|||||||
public PendingIntent contentIntent;
|
public PendingIntent contentIntent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The intent to execute when the status entry is deleted by the user
|
* The intent to execute when the notification is explicitly dismissed by the user, either with
|
||||||
* with the "Clear All Notifications" button. This probably shouldn't
|
* the "Clear All" button or by swiping it away individually.
|
||||||
* be launching an activity since several of those will be sent at the
|
*
|
||||||
* same time.
|
* This probably shouldn't be launching an activity since several of those will be sent
|
||||||
|
* at the same time.
|
||||||
*/
|
*/
|
||||||
public PendingIntent deleteIntent;
|
public PendingIntent deleteIntent;
|
||||||
|
|
||||||
@ -139,11 +170,6 @@ public class Notification implements Parcelable
|
|||||||
* Text to scroll across the screen when this item is added to
|
* Text to scroll across the screen when this item is added to
|
||||||
* the status bar on large and smaller devices.
|
* 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
|
* @see #tickerView
|
||||||
*/
|
*/
|
||||||
public CharSequence tickerText;
|
public CharSequence tickerText;
|
||||||
@ -166,9 +192,9 @@ public class Notification implements Parcelable
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The sound to play.
|
* The sound to play.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* To play the default notification sound, see {@link #defaults}.
|
* To play the default notification sound, see {@link #defaults}.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public Uri sound;
|
public Uri sound;
|
||||||
@ -187,14 +213,13 @@ public class Notification implements Parcelable
|
|||||||
*/
|
*/
|
||||||
public int audioStreamType = STREAM_DEFAULT;
|
public int audioStreamType = STREAM_DEFAULT;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The pattern with which to vibrate.
|
* The pattern with which to vibrate.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* To vibrate the default pattern, see {@link #defaults}.
|
* To vibrate the default pattern, see {@link #defaults}.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @see android.os.Vibrator#vibrate(long[],int)
|
* @see android.os.Vibrator#vibrate(long[],int)
|
||||||
*/
|
*/
|
||||||
public long[] vibrate;
|
public long[] vibrate;
|
||||||
@ -235,7 +260,6 @@ public class Notification implements Parcelable
|
|||||||
*/
|
*/
|
||||||
public int defaults;
|
public int defaults;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bit to be bitwise-ored into the {@link #flags} field that should be
|
* Bit to be bitwise-ored into the {@link #flags} field that should be
|
||||||
* set if you want the LED on for this notification.
|
* 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.
|
* because they will be set to values that work on any given hardware.
|
||||||
* <p>
|
* <p>
|
||||||
* The alpha channel must be set for forward compatibility.
|
* The alpha channel must be set for forward compatibility.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static final int FLAG_SHOW_LIGHTS = 0x00000001;
|
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
|
* 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
|
* 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;
|
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;
|
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
|
* Obsolete flag indicating high-priority notifications; use the priority field instead.
|
||||||
* 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
|
* @deprecated Use {@link #priority} with a positive value.
|
||||||
* in conjunction with {@link #fullScreenIntent}.
|
|
||||||
*/
|
*/
|
||||||
public static final int FLAG_HIGH_PRIORITY = 0x00000080;
|
public static final int FLAG_HIGH_PRIORITY = 0x00000080;
|
||||||
|
|
||||||
public int flags;
|
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.
|
* You might want to consider using {@link Builder} instead.
|
||||||
*/
|
*/
|
||||||
public Notification()
|
public Notification()
|
||||||
{
|
{
|
||||||
this.when = System.currentTimeMillis();
|
this.when = System.currentTimeMillis();
|
||||||
|
this.priority = PRIORITY_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -396,6 +504,14 @@ public class Notification implements Parcelable
|
|||||||
if (parcel.readInt() != 0) {
|
if (parcel.readInt() != 0) {
|
||||||
fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
|
fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
priority = parcel.readInt();
|
||||||
|
|
||||||
|
kind = parcel.createStringArray(); // may set kind to null
|
||||||
|
|
||||||
|
if (parcel.readInt() != 0) {
|
||||||
|
extras = parcel.readBundle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -438,9 +554,23 @@ public class Notification implements Parcelable
|
|||||||
that.ledOnMS = this.ledOnMS;
|
that.ledOnMS = this.ledOnMS;
|
||||||
that.ledOffMS = this.ledOffMS;
|
that.ledOffMS = this.ledOffMS;
|
||||||
that.defaults = this.defaults;
|
that.defaults = this.defaults;
|
||||||
|
|
||||||
that.flags = this.flags;
|
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;
|
return that;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,6 +647,17 @@ public class Notification implements Parcelable
|
|||||||
} else {
|
} else {
|
||||||
parcel.writeInt(0);
|
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
|
* 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
|
* <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
|
||||||
* Stack</a> document.
|
* Stack</a> document.
|
||||||
*
|
*
|
||||||
* @deprecated Use {@link Builder} instead.
|
* @deprecated Use {@link Builder} instead.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@ -579,7 +720,9 @@ public class Notification implements Parcelable
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("Notification(contentView=");
|
sb.append("Notification(pri=");
|
||||||
|
sb.append(priority);
|
||||||
|
sb.append(" contentView=");
|
||||||
if (contentView != null) {
|
if (contentView != null) {
|
||||||
sb.append(contentView.getPackage());
|
sb.append(contentView.getPackage());
|
||||||
sb.append("/0x");
|
sb.append("/0x");
|
||||||
@ -587,6 +730,7 @@ public class Notification implements Parcelable
|
|||||||
} else {
|
} else {
|
||||||
sb.append("null");
|
sb.append("null");
|
||||||
}
|
}
|
||||||
|
// TODO(dsandler): defaults take precedence over local values, so reorder the branches below
|
||||||
sb.append(" vibrate=");
|
sb.append(" vibrate=");
|
||||||
if (this.vibrate != null) {
|
if (this.vibrate != null) {
|
||||||
int N = this.vibrate.length-1;
|
int N = this.vibrate.length-1;
|
||||||
@ -604,7 +748,7 @@ public class Notification implements Parcelable
|
|||||||
} else {
|
} else {
|
||||||
sb.append("null");
|
sb.append("null");
|
||||||
}
|
}
|
||||||
sb.append(",sound=");
|
sb.append(" sound=");
|
||||||
if (this.sound != null) {
|
if (this.sound != null) {
|
||||||
sb.append(this.sound.toString());
|
sb.append(this.sound.toString());
|
||||||
} else if ((this.defaults & DEFAULT_SOUND) != 0) {
|
} else if ((this.defaults & DEFAULT_SOUND) != 0) {
|
||||||
@ -612,20 +756,39 @@ public class Notification implements Parcelable
|
|||||||
} else {
|
} else {
|
||||||
sb.append("null");
|
sb.append("null");
|
||||||
}
|
}
|
||||||
sb.append(",defaults=0x");
|
sb.append(" defaults=0x");
|
||||||
sb.append(Integer.toHexString(this.defaults));
|
sb.append(Integer.toHexString(this.defaults));
|
||||||
sb.append(",flags=0x");
|
sb.append(" flags=0x");
|
||||||
sb.append(Integer.toHexString(this.flags));
|
sb.append(Integer.toHexString(this.flags));
|
||||||
if ((this.flags & FLAG_HIGH_PRIORITY) != 0) {
|
sb.append(" kind=[");
|
||||||
sb.append("!!!1!one!");
|
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();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder class for {@link Notification} objects. Allows easier control over
|
* Builder class for {@link Notification} objects.
|
||||||
* all the flags, as well as help constructing the typical notification layouts.
|
*
|
||||||
|
* 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 {
|
public static class Builder {
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
@ -655,16 +818,28 @@ public class Notification implements Parcelable
|
|||||||
private int mProgressMax;
|
private int mProgressMax;
|
||||||
private int mProgress;
|
private int mProgress;
|
||||||
private boolean mProgressIndeterminate;
|
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
|
* @param context
|
||||||
* Builder object.
|
* 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) {
|
public Builder(Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
@ -672,11 +847,14 @@ public class Notification implements Parcelable
|
|||||||
// Set defaults to match the defaults of a Notification
|
// Set defaults to match the defaults of a Notification
|
||||||
mWhen = System.currentTimeMillis();
|
mWhen = System.currentTimeMillis();
|
||||||
mAudioStreamType = STREAM_DEFAULT;
|
mAudioStreamType = STREAM_DEFAULT;
|
||||||
|
mPriority = PRIORITY_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the time that the event occurred. Notifications in the panel are
|
* Add a timestamp pertaining to the notification (usually the time the event occurred).
|
||||||
* sorted by this time.
|
*
|
||||||
|
|
||||||
|
* @see Notification#when
|
||||||
*/
|
*/
|
||||||
public Builder setWhen(long when) {
|
public Builder setWhen(long when) {
|
||||||
mWhen = 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
|
* Set the small icon resource, which will be used to represent the notification in the
|
||||||
* may return different sizes. See the UX guidelines for more information on how to
|
* status bar.
|
||||||
* design these icons.
|
|
||||||
*
|
*
|
||||||
* @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) {
|
public Builder setSmallIcon(int icon) {
|
||||||
mSmallIcon = 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
|
* level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
|
||||||
* 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.
|
* @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) {
|
public Builder setSmallIcon(int icon, int level) {
|
||||||
mSmallIcon = icon;
|
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) {
|
public Builder setContentTitle(CharSequence title) {
|
||||||
mContentTitle = 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) {
|
public Builder setContentText(CharSequence text) {
|
||||||
mContentText = 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) {
|
public Builder setContentInfo(CharSequence info) {
|
||||||
mContentInfo = info;
|
mContentInfo = info;
|
||||||
@ -746,8 +936,10 @@ public class Notification implements Parcelable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the progress this notification represents, which may be
|
* Set the progress this notification represents.
|
||||||
* represented as a {@link ProgressBar}.
|
*
|
||||||
|
|
||||||
|
* The platform template will represent this using a {@link ProgressBar}.
|
||||||
*/
|
*/
|
||||||
public Builder setProgress(int max, int progress, boolean indeterminate) {
|
public Builder setProgress(int max, int progress, boolean indeterminate) {
|
||||||
mProgressMax = max;
|
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) {
|
public Builder setContent(RemoteViews views) {
|
||||||
mContentView = views;
|
mContentView = views;
|
||||||
@ -765,12 +960,20 @@ public class Notification implements Parcelable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supply a {@link PendingIntent} to send when the notification is clicked.
|
* Supply a {@link PendingIntent} to be sent 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
|
* As of {@link android.os.Build.VERSION_CODES#HONEYCOMB}, if this field is unset and you
|
||||||
* read {@link Notification#contentIntent Notification.contentIntent} for
|
* have specified a custom RemoteViews with {@link #setContent(RemoteViews)}, you can use
|
||||||
* how to correctly use this.
|
* {@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) {
|
public Builder setContentIntent(PendingIntent intent) {
|
||||||
mContentIntent = 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
|
* Supply a {@link PendingIntent} to send when the notification is cleared explicitly 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
|
* @see Notification#deleteIntent
|
||||||
* NotificationManager.cancel(int)}.
|
|
||||||
*/
|
*/
|
||||||
public Builder setDeleteIntent(PendingIntent intent) {
|
public Builder setDeleteIntent(PendingIntent intent) {
|
||||||
mDeleteIntent = intent;
|
mDeleteIntent = intent;
|
||||||
@ -801,6 +1003,8 @@ public class Notification implements Parcelable
|
|||||||
* @param intent The pending intent to launch.
|
* @param intent The pending intent to launch.
|
||||||
* @param highPriority Passing true will cause this notification to be sent
|
* @param highPriority Passing true will cause this notification to be sent
|
||||||
* even if other notifications are suppressed.
|
* even if other notifications are suppressed.
|
||||||
|
*
|
||||||
|
* @see Notification#fullScreenIntent
|
||||||
*/
|
*/
|
||||||
public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
|
public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
|
||||||
mFullScreenIntent = intent;
|
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.
|
* arrives.
|
||||||
|
*
|
||||||
|
|
||||||
|
* @see Notification#tickerText
|
||||||
*/
|
*/
|
||||||
public Builder setTicker(CharSequence tickerText) {
|
public Builder setTicker(CharSequence tickerText) {
|
||||||
mTickerText = 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
|
* 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
|
* arrives, and also a RemoteViews object that may be displayed instead on some
|
||||||
* devices.
|
* devices.
|
||||||
|
*
|
||||||
|
* @see Notification#tickerText
|
||||||
|
* @see Notification#tickerView
|
||||||
*/
|
*/
|
||||||
public Builder setTicker(CharSequence tickerText, RemoteViews views) {
|
public Builder setTicker(CharSequence tickerText, RemoteViews views) {
|
||||||
mTickerText = tickerText;
|
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) {
|
public Builder setLargeIcon(Bitmap icon) {
|
||||||
mLargeIcon = 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) {
|
public Builder setSound(Uri sound) {
|
||||||
mSound = 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 {@link android.media.AudioManager} for the <code>STREAM_</code> constants.
|
||||||
* @see AudioManager for the <code>STREAM_</code> constants.
|
*
|
||||||
|
* @see Notification#sound
|
||||||
*/
|
*/
|
||||||
public Builder setSound(Uri sound, int streamType) {
|
public Builder setSound(Uri sound, int streamType) {
|
||||||
mSound = sound;
|
mSound = sound;
|
||||||
@ -860,8 +1080,12 @@ public class Notification implements Parcelable
|
|||||||
/**
|
/**
|
||||||
* Set the vibration pattern to use.
|
* 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) {
|
public Builder setVibrate(long[] pattern) {
|
||||||
mVibrate = 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
|
* Set the desired color for the indicator LED on the device, as well as the
|
||||||
* rate. The rate is specified in terms of the number of milliseconds to be on
|
* blink duty cycle (specified in milliseconds).
|
||||||
* and then the number of milliseconds to be off.
|
*
|
||||||
|
|
||||||
|
* 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) {
|
public Builder setLights(int argb, int onMs, int offMs) {
|
||||||
mLedArgb = argb;
|
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>
|
* Ongoing notifications cannot be dismissed by the user, so your application or service
|
||||||
* <li>Ongoing notifications are sorted above the regular notifications in the
|
* must take care of canceling them.
|
||||||
* notification panel.</li>
|
*
|
||||||
* <li>Ongoing notifications do not have an 'X' close button, and are not affected
|
|
||||||
* by the "Clear all" button.
|
* They are typically used to indicate a background task that the user is actively engaged
|
||||||
* </ul>
|
* 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) {
|
public Builder setOngoing(boolean ongoing) {
|
||||||
setFlag(FLAG_ONGOING_EVENT, 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
|
* Set this flag if you would only like the sound, vibrate
|
||||||
* and ticker to be played if the notification is not already showing.
|
* and ticker to be played if the notification is not already showing.
|
||||||
|
*
|
||||||
|
* @see Notification#FLAG_ONLY_ALERT_ONCE
|
||||||
*/
|
*/
|
||||||
public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
|
public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
|
||||||
setFlag(FLAG_ONLY_ALERT_ONCE, 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
|
* Make this notification automatically dismissed when the user touches it. The
|
||||||
* canceled when the user clicks it in the panel. The PendingIntent
|
* PendingIntent set with {@link #setDeleteIntent} will be sent when this happens.
|
||||||
* set with {@link #setDeleteIntent} will be broadcast when the notification
|
*
|
||||||
* is canceled.
|
* @see Notification#FLAG_AUTO_CANCEL
|
||||||
*/
|
*/
|
||||||
public Builder setAutoCancel(boolean autoCancel) {
|
public Builder setAutoCancel(boolean autoCancel) {
|
||||||
setFlag(FLAG_AUTO_CANCEL, 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>
|
* <p>
|
||||||
* The value should be one or more of the following fields combined with
|
* The value should be one or more of the following fields combined with
|
||||||
* bitwise-or:
|
* bitwise-or:
|
||||||
@ -930,6 +1168,41 @@ public class Notification implements Parcelable
|
|||||||
return this;
|
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) {
|
private void setFlag(int mask, boolean value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
mFlags |= mask;
|
mFlags |= mask;
|
||||||
@ -1042,6 +1315,14 @@ public class Notification implements Parcelable
|
|||||||
if ((mDefaults & DEFAULT_LIGHTS) != 0) {
|
if ((mDefaults & DEFAULT_LIGHTS) != 0) {
|
||||||
n.flags |= FLAG_SHOW_LIGHTS;
|
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;
|
return n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 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 String pkg;
|
||||||
public int id;
|
public int id;
|
||||||
public String tag;
|
public String tag;
|
||||||
public int uid;
|
public int uid;
|
||||||
public int initialPid;
|
public int initialPid;
|
||||||
public Notification notification;
|
public Notification notification;
|
||||||
public int priority = PRIORITY_NORMAL;
|
public int score;
|
||||||
|
|
||||||
public StatusBarNotification() {
|
public StatusBarNotification() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatusBarNotification(String pkg, int id, String tag,
|
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 (pkg == null) throw new NullPointerException();
|
||||||
if (notification == null) throw new NullPointerException();
|
if (notification == null) throw new NullPointerException();
|
||||||
|
|
||||||
@ -61,9 +59,8 @@ public class StatusBarNotification implements Parcelable {
|
|||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
this.uid = uid;
|
this.uid = uid;
|
||||||
this.initialPid = initialPid;
|
this.initialPid = initialPid;
|
||||||
|
this.score = score;
|
||||||
this.notification = notification;
|
this.notification = notification;
|
||||||
|
|
||||||
this.priority = PRIORITY_NORMAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatusBarNotification(Parcel in) {
|
public StatusBarNotification(Parcel in) {
|
||||||
@ -80,7 +77,7 @@ public class StatusBarNotification implements Parcelable {
|
|||||||
}
|
}
|
||||||
this.uid = in.readInt();
|
this.uid = in.readInt();
|
||||||
this.initialPid = in.readInt();
|
this.initialPid = in.readInt();
|
||||||
this.priority = in.readInt();
|
this.score = in.readInt();
|
||||||
this.notification = new Notification(in);
|
this.notification = new Notification(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +92,7 @@ public class StatusBarNotification implements Parcelable {
|
|||||||
}
|
}
|
||||||
out.writeInt(this.uid);
|
out.writeInt(this.uid);
|
||||||
out.writeInt(this.initialPid);
|
out.writeInt(this.initialPid);
|
||||||
out.writeInt(this.priority);
|
out.writeInt(this.score);
|
||||||
this.notification.writeToParcel(out, flags);
|
this.notification.writeToParcel(out, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,12 +116,12 @@ public class StatusBarNotification implements Parcelable {
|
|||||||
|
|
||||||
public StatusBarNotification clone() {
|
public StatusBarNotification clone() {
|
||||||
return new StatusBarNotification(this.pkg, this.id, this.tag,
|
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() {
|
public String toString() {
|
||||||
return "StatusBarNotification(package=" + pkg + " id=" + id + " tag=" + tag
|
return "StatusBarNotification(pkg=" + pkg + " id=" + id + " tag=" + tag
|
||||||
+ " notification=" + notification + " priority=" + priority + ")";
|
+ " score=" + score + " notn=" + notification + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOngoing() {
|
public boolean isOngoing() {
|
||||||
|
@ -47,12 +47,13 @@ public class NotificationData {
|
|||||||
}
|
}
|
||||||
private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
|
private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
|
||||||
private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() {
|
private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() {
|
||||||
|
// sort first by score, then by when
|
||||||
public int compare(Entry a, Entry b) {
|
public int compare(Entry a, Entry b) {
|
||||||
final StatusBarNotification na = a.notification;
|
final StatusBarNotification na = a.notification;
|
||||||
final StatusBarNotification nb = b.notification;
|
final StatusBarNotification nb = b.notification;
|
||||||
int priDiff = na.priority - nb.priority;
|
int d = na.score - nb.score;
|
||||||
return (priDiff != 0)
|
return (d != 0)
|
||||||
? priDiff
|
? d
|
||||||
: (int)(na.notification.when - nb.notification.when);
|
: (int)(na.notification.when - nb.notification.when);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -232,6 +232,11 @@ public class PhoneStatusBar extends StatusBar {
|
|||||||
|
|
||||||
private int mNavigationIconHints = 0;
|
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 {
|
private class ExpandedDialog extends Dialog {
|
||||||
ExpandedDialog(Context context) {
|
ExpandedDialog(Context context) {
|
||||||
super(context, com.android.internal.R.style.Theme_Translucent_NoTitleBar);
|
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) {
|
public void addNotification(IBinder key, StatusBarNotification notification) {
|
||||||
|
/* if (DEBUG) */ Slog.d(TAG, "addNotification score=" + notification.score);
|
||||||
StatusBarIconView iconView = addNotificationViews(key, notification);
|
StatusBarIconView iconView = addNotificationViews(key, notification);
|
||||||
if (iconView == null) return;
|
if (iconView == null) return;
|
||||||
|
|
||||||
@ -549,31 +555,30 @@ public class PhoneStatusBar extends StatusBar {
|
|||||||
}
|
}
|
||||||
} catch (RemoteException ex) {
|
} catch (RemoteException ex) {
|
||||||
}
|
}
|
||||||
if (immersive) {
|
if ((notification.score >= mIntruderInImmersiveMinScore)
|
||||||
if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) {
|
|| (!immersive && (notification.score > mIntruderMinScore))) {
|
||||||
Slog.d(TAG, "Presenting high-priority notification in immersive activity");
|
Slog.d(TAG, "Presenting high-priority notification");
|
||||||
// special new transient ticker mode
|
// special new transient ticker mode
|
||||||
// 1. Populate mIntruderAlertView
|
// 1. Populate mIntruderAlertView
|
||||||
|
|
||||||
ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon);
|
ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon);
|
||||||
TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText);
|
TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText);
|
||||||
alertIcon.setImageDrawable(StatusBarIconView.getIcon(
|
alertIcon.setImageDrawable(StatusBarIconView.getIcon(
|
||||||
alertIcon.getContext(),
|
alertIcon.getContext(),
|
||||||
iconView.getStatusBarIcon()));
|
iconView.getStatusBarIcon()));
|
||||||
alertText.setText(notification.notification.tickerText);
|
alertText.setText(notification.notification.tickerText);
|
||||||
|
|
||||||
View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content);
|
View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content);
|
||||||
button.setOnClickListener(
|
button.setOnClickListener(
|
||||||
new NotificationClicker(notification.notification.contentIntent,
|
new NotificationClicker(notification.notification.contentIntent,
|
||||||
notification.pkg, notification.tag, notification.id));
|
notification.pkg, notification.tag, notification.id));
|
||||||
|
|
||||||
// 2. Animate mIntruderAlertView in
|
// 2. Animate mIntruderAlertView in
|
||||||
mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
|
mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
|
||||||
|
|
||||||
// 3. Set alarm to age the notification off (TODO)
|
// 3. Set alarm to age the notification off (TODO)
|
||||||
mHandler.removeMessages(MSG_HIDE_INTRUDER);
|
mHandler.removeMessages(MSG_HIDE_INTRUDER);
|
||||||
mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
|
mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
|
||||||
}
|
|
||||||
} else if (notification.notification.fullScreenIntent != null) {
|
} else if (notification.notification.fullScreenIntent != null) {
|
||||||
// not immersive & a full-screen alert should be shown
|
// not immersive & a full-screen alert should be shown
|
||||||
Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
|
Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
|
||||||
@ -630,8 +635,8 @@ public class PhoneStatusBar extends StatusBar {
|
|||||||
&& oldContentView.getLayoutId() == contentView.getLayoutId();
|
&& oldContentView.getLayoutId() == contentView.getLayoutId();
|
||||||
ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
|
ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
|
||||||
boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
|
boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
|
||||||
&& notification.priority == oldNotification.priority;
|
&& notification.score == oldNotification.score;
|
||||||
// priority now encompasses isOngoing()
|
// score now encompasses/supersedes isOngoing()
|
||||||
|
|
||||||
boolean updateTicker = notification.notification.tickerText != null
|
boolean updateTicker = notification.notification.tickerText != null
|
||||||
&& !TextUtils.equals(notification.notification.tickerText,
|
&& !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) {
|
StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "addNotificationViews(key=" + key + ", notification=" + notification);
|
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++) {
|
for (int i=0; i<toShow.size(); i++) {
|
||||||
View v = toShow.get(i);
|
View v = toShow.get(i);
|
||||||
if (v.getParent() == null) {
|
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);
|
NotificationData.Entry e = mNotificationData.get(i);
|
||||||
pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon);
|
pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon);
|
||||||
StatusBarNotification n = e.notification;
|
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(" notification=" + n.notification);
|
||||||
pw.println(" tickerText=\"" + n.notification.tickerText + "\"");
|
pw.println(" tickerText=\"" + n.notification.tickerText + "\"");
|
||||||
}
|
}
|
||||||
@ -2315,6 +2257,30 @@ public class PhoneStatusBar extends StatusBar {
|
|||||||
vib.vibrate(250);
|
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() {
|
Runnable mStartTracing = new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
vibrate();
|
vibrate();
|
||||||
|
@ -99,13 +99,14 @@ public class LocationController extends BroadcastReceiver {
|
|||||||
// Notification.Builder will helpfully fill these out for you no matter what you do
|
// Notification.Builder will helpfully fill these out for you no matter what you do
|
||||||
n.tickerView = null;
|
n.tickerView = null;
|
||||||
n.tickerText = null;
|
n.tickerText = null;
|
||||||
|
|
||||||
|
n.priority = Notification.PRIORITY_HIGH;
|
||||||
|
|
||||||
int[] idOut = new int[1];
|
int[] idOut = new int[1];
|
||||||
mNotificationService.enqueueNotificationWithTagPriority(
|
mNotificationService.enqueueNotificationWithTag(
|
||||||
mContext.getPackageName(),
|
mContext.getPackageName(),
|
||||||
null,
|
null,
|
||||||
GPS_NOTIFICATION_ID,
|
GPS_NOTIFICATION_ID,
|
||||||
StatusBarNotification.PRIORITY_SYSTEM, // !!!1!one!!!
|
|
||||||
n,
|
n,
|
||||||
idOut);
|
idOut);
|
||||||
} else {
|
} else {
|
||||||
|
@ -860,8 +860,8 @@ public class TabletStatusBar extends StatusBar implements
|
|||||||
&& oldContentView.getLayoutId() == contentView.getLayoutId();
|
&& oldContentView.getLayoutId() == contentView.getLayoutId();
|
||||||
ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
|
ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
|
||||||
boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
|
boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
|
||||||
&& notification.priority == oldNotification.priority;
|
&& notification.score == oldNotification.score;
|
||||||
// priority now encompasses isOngoing()
|
// score now encompasses/supersedes isOngoing()
|
||||||
boolean updateTicker = notification.notification.tickerText != null
|
boolean updateTicker = notification.notification.tickerText != null
|
||||||
&& !TextUtils.equals(notification.notification.tickerText,
|
&& !TextUtils.equals(notification.notification.tickerText,
|
||||||
oldEntry.notification.notification.tickerText);
|
oldEntry.notification.notification.tickerText);
|
||||||
@ -1689,7 +1689,7 @@ public class TabletStatusBar extends StatusBar implements
|
|||||||
|
|
||||||
mNotificationDNDDummyEntry = new NotificationData.Entry(
|
mNotificationDNDDummyEntry = new NotificationData.Entry(
|
||||||
null,
|
null,
|
||||||
new StatusBarNotification("", 0, "", 0, 0, dndNotification),
|
new StatusBarNotification("", 0, "", 0, 0, Notification.PRIORITY_MAX, dndNotification),
|
||||||
iconView);
|
iconView);
|
||||||
|
|
||||||
mIconLayout.addView(iconView, params);
|
mIconLayout.addView(iconView, params);
|
||||||
|
@ -146,19 +146,18 @@ public class NotificationManagerService extends INotificationManager.Stub
|
|||||||
final int id;
|
final int id;
|
||||||
final int uid;
|
final int uid;
|
||||||
final int initialPid;
|
final int initialPid;
|
||||||
final int priority;
|
|
||||||
final Notification notification;
|
final Notification notification;
|
||||||
|
final int score;
|
||||||
IBinder statusBarKey;
|
IBinder statusBarKey;
|
||||||
|
|
||||||
NotificationRecord(String pkg, String tag, int id, int uid, int initialPid, int priority,
|
NotificationRecord(String pkg, String tag, int id, int uid, int initialPid, int score, Notification notification)
|
||||||
Notification notification)
|
|
||||||
{
|
{
|
||||||
this.pkg = pkg;
|
this.pkg = pkg;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.uid = uid;
|
this.uid = uid;
|
||||||
this.initialPid = initialPid;
|
this.initialPid = initialPid;
|
||||||
this.priority = priority;
|
this.score = score;
|
||||||
this.notification = notification;
|
this.notification = notification;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,6 +165,8 @@ public class NotificationManagerService extends INotificationManager.Stub
|
|||||||
pw.println(prefix + this);
|
pw.println(prefix + this);
|
||||||
pw.println(prefix + " icon=0x" + Integer.toHexString(notification.icon)
|
pw.println(prefix + " icon=0x" + Integer.toHexString(notification.icon)
|
||||||
+ " / " + idDebugString(baseContext, this.pkg, 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 + " contentIntent=" + notification.contentIntent);
|
||||||
pw.println(prefix + " deleteIntent=" + notification.deleteIntent);
|
pw.println(prefix + " deleteIntent=" + notification.deleteIntent);
|
||||||
pw.println(prefix + " tickerText=" + notification.tickerText);
|
pw.println(prefix + " tickerText=" + notification.tickerText);
|
||||||
@ -187,7 +188,7 @@ public class NotificationManagerService extends INotificationManager.Stub
|
|||||||
+ " pkg=" + pkg
|
+ " pkg=" + pkg
|
||||||
+ " id=" + Integer.toHexString(id)
|
+ " id=" + Integer.toHexString(id)
|
||||||
+ " tag=" + tag
|
+ " tag=" + tag
|
||||||
+ " pri=" + priority
|
+ " score=" + score
|
||||||
+ "}";
|
+ "}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -660,27 +661,16 @@ public class NotificationManagerService extends INotificationManager.Stub
|
|||||||
enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),
|
enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),
|
||||||
tag, id, notification, idOut);
|
tag, id, notification, idOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enqueueNotificationWithTagPriority(String pkg, String tag, int id, int priority,
|
private final static int clamp(int x, int low, int high) {
|
||||||
Notification notification, int[] idOut)
|
return (x < low) ? low : ((x > high) ? high : x);
|
||||||
{
|
|
||||||
enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),
|
|
||||||
tag, id, priority, notification, idOut);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
|
// Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
|
||||||
// uid/pid of another application)
|
// uid/pid of another application)
|
||||||
public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,
|
public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,
|
||||||
String tag, int id, Notification notification, int[] idOut)
|
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);
|
checkIncomingCall(pkg);
|
||||||
|
|
||||||
@ -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) {
|
synchronized (mNotificationList) {
|
||||||
NotificationRecord r = new NotificationRecord(pkg, tag, id,
|
NotificationRecord r = new NotificationRecord(pkg, tag, id,
|
||||||
callingUid, callingPid,
|
callingUid, callingPid,
|
||||||
priority,
|
score,
|
||||||
notification);
|
notification);
|
||||||
NotificationRecord old = null;
|
NotificationRecord old = null;
|
||||||
|
|
||||||
@ -752,9 +767,7 @@ public class NotificationManagerService extends INotificationManager.Stub
|
|||||||
|
|
||||||
if (notification.icon != 0) {
|
if (notification.icon != 0) {
|
||||||
StatusBarNotification n = new StatusBarNotification(pkg, id, tag,
|
StatusBarNotification n = new StatusBarNotification(pkg, id, tag,
|
||||||
r.uid, r.initialPid, notification);
|
r.uid, r.initialPid, score, notification);
|
||||||
n.priority = r.priority;
|
|
||||||
|
|
||||||
if (old != null && old.statusBarKey != null) {
|
if (old != null && old.statusBarKey != null) {
|
||||||
r.statusBarKey = old.statusBarKey;
|
r.statusBarKey = old.statusBarKey;
|
||||||
long identity = Binder.clearCallingIdentity();
|
long identity = Binder.clearCallingIdentity();
|
||||||
|
@ -765,22 +765,70 @@ public class NotificationTestList extends TestActivity
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
new Test("System priority notification") {
|
new Test("PRIORITY_HIGH") {
|
||||||
public void run() {
|
public void run() {
|
||||||
Notification n = new Notification.Builder(NotificationTestList.this)
|
Notification n = new Notification.Builder(NotificationTestList.this)
|
||||||
.setSmallIcon(R.drawable.notification1)
|
.setSmallIcon(R.drawable.notification5)
|
||||||
.setContentTitle("System priority")
|
.setContentTitle("High priority")
|
||||||
.setContentText("This should appear before all others")
|
.setContentText("This should appear before all others")
|
||||||
|
.setPriority(Notification.PRIORITY_HIGH)
|
||||||
.getNotification();
|
.getNotification();
|
||||||
|
|
||||||
int[] idOut = new int[1];
|
int[] idOut = new int[1];
|
||||||
try {
|
try {
|
||||||
INotificationManager directLine = mNM.getService();
|
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(),
|
getPackageName(),
|
||||||
null,
|
null,
|
||||||
1,
|
1,
|
||||||
StatusBarNotification.PRIORITY_SYSTEM,
|
|
||||||
n,
|
n,
|
||||||
idOut);
|
idOut);
|
||||||
} catch (android.os.RemoteException ex) {
|
} catch (android.os.RemoteException ex) {
|
||||||
|
Reference in New Issue
Block a user