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:
Daniel Sandler
2012-02-13 21:04:12 -05:00
parent c725a3705b
commit 2561b0b10a
10 changed files with 568 additions and 248 deletions

View File

@ -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,27 +661,16 @@ 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);
@ -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();