am 54c4c19b: Merge "NotificationListenerService: API updates" into lmp-preview-dev

* commit '54c4c19bc95e839cfce3d10f0e842ed5588391eb':
  NotificationListenerService: API updates
This commit is contained in:
Dan Sandler
2014-06-12 00:04:01 +00:00
committed by Android Git Automerger
7 changed files with 219 additions and 118 deletions

View File

@@ -26015,21 +26015,28 @@ package android.service.notification {
method public final void cancelNotification(java.lang.String);
method public final void cancelNotifications(java.lang.String[]);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
method public android.service.notification.NotificationListenerService.Ranking getCurrentRanking();
method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
method public android.os.IBinder onBind(android.content.Intent);
method public void onListenerConnected();
method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
method public void onNotificationRankingUpdate();
method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
method public void onNotificationPosted(android.service.notification.StatusBarNotification);
method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
}
public static class NotificationListenerService.Ranking implements android.os.Parcelable {
public static class NotificationListenerService.Ranking {
method public java.lang.String getKey();
method public int getRank();
method public boolean isAmbient();
method public boolean isInterceptedByDoNotDisturb();
}
public static class NotificationListenerService.RankingMap implements android.os.Parcelable {
method public int describeContents();
method public java.lang.String[] getOrderedKeys();
method public int getRank(java.lang.String);
method public boolean isAmbient(java.lang.String);
method public boolean isInterceptedByDoNotDisturb(java.lang.String);
method public android.service.notification.NotificationListenerService.Ranking getRanking(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}

View File

@@ -29,6 +29,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;
import java.util.List;
@@ -54,7 +55,7 @@ public abstract class NotificationListenerService extends Service {
+ "[" + getClass().getSimpleName() + "]";
private INotificationListenerWrapper mWrapper = null;
private Ranking mRanking;
private RankingMap mRankingMap;
private INotificationManager mNoMan;
@@ -75,7 +76,22 @@ public abstract class NotificationListenerService extends Service {
* object as well as its identifying information (tag and id) and source
* (package name).
*/
public abstract void onNotificationPosted(StatusBarNotification sbn);
public void onNotificationPosted(StatusBarNotification sbn) {
// optional
}
/**
* Implement this method to learn about new notifications as they are posted by apps.
*
* @param sbn A data structure encapsulating the original {@link android.app.Notification}
* object as well as its identifying information (tag and id) and source
* (package name).
* @param rankingMap The current ranking map that can be used to retrieve ranking information
* for active notifications, including the newly posted one.
*/
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
onNotificationPosted(sbn);
}
/**
* Implement this method to learn when notifications are removed.
@@ -94,7 +110,33 @@ public abstract class NotificationListenerService extends Service {
* and source (package name) used to post the {@link android.app.Notification} that
* was just removed.
*/
public abstract void onNotificationRemoved(StatusBarNotification sbn);
public void onNotificationRemoved(StatusBarNotification sbn) {
// optional
}
/**
* Implement this method to learn when notifications are removed.
* <P>
* This might occur because the user has dismissed the notification using system UI (or another
* notification listener) or because the app has withdrawn the notification.
* <P>
* NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
* result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
* fields such as {@link android.app.Notification#contentView} and
* {@link android.app.Notification#largeIcon}. However, all other fields on
* {@link StatusBarNotification}, sufficient to match this call with a prior call to
* {@link #onNotificationPosted(StatusBarNotification)}, will be intact.
*
* @param sbn A data structure encapsulating at least the original information (tag and id)
* and source (package name) used to post the {@link android.app.Notification} that
* was just removed.
* @param rankingMap The current ranking map that can be used to retrieve ranking information
* for active notifications.
*
*/
public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
onNotificationRemoved(sbn);
}
/**
* Implement this method to learn about when the listener is enabled and connected to
@@ -107,10 +149,11 @@ public abstract class NotificationListenerService extends Service {
/**
* Implement this method to be notified when the notification ranking changes.
* <P>
* Call {@link #getCurrentRanking()} to retrieve the new ranking.
*
* @param rankingMap The current ranking map that can be used to retrieve ranking information
* for active notifications.
*/
public void onNotificationRankingUpdate() {
public void onNotificationRankingUpdate(RankingMap rankingMap) {
// optional
}
@@ -241,16 +284,19 @@ public abstract class NotificationListenerService extends Service {
*
* <p>
* The returned object represents the current ranking snapshot and only
* applies for currently active notifications. Hence you must retrieve a
* new Ranking after each notification event such as
* {@link #onNotificationPosted(StatusBarNotification)},
* {@link #onNotificationRemoved(StatusBarNotification)}, etc.
* applies for currently active notifications.
* <p>
* Generally you should use the RankingMap that is passed with events such
* as {@link #onNotificationPosted(StatusBarNotification, RankingMap)},
* {@link #onNotificationRemoved(StatusBarNotification, RankingMap)}, and
* so on. This method should only be used when needing access outside of
* such events, for example to retrieve the RankingMap right after
* initialization.
*
* @return A {@link NotificationListenerService.Ranking} object providing
* access to ranking information
* @return A {@link RankingMap} object providing access to ranking information
*/
public Ranking getCurrentRanking() {
return mRanking;
public RankingMap getCurrentRanking() {
return mRankingMap;
}
@Override
@@ -313,7 +359,7 @@ public abstract class NotificationListenerService extends Service {
synchronized (mWrapper) {
applyUpdate(update);
try {
NotificationListenerService.this.onNotificationPosted(sbn);
NotificationListenerService.this.onNotificationPosted(sbn, mRankingMap);
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationPosted", t);
}
@@ -326,7 +372,7 @@ public abstract class NotificationListenerService extends Service {
synchronized (mWrapper) {
applyUpdate(update);
try {
NotificationListenerService.this.onNotificationRemoved(sbn);
NotificationListenerService.this.onNotificationRemoved(sbn, mRankingMap);
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationRemoved", t);
}
@@ -351,7 +397,7 @@ public abstract class NotificationListenerService extends Service {
synchronized (mWrapper) {
applyUpdate(update);
try {
NotificationListenerService.this.onNotificationRankingUpdate();
NotificationListenerService.this.onNotificationRankingUpdate(mRankingMap);
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationRankingUpdate", t);
}
@@ -360,7 +406,65 @@ public abstract class NotificationListenerService extends Service {
}
private void applyUpdate(NotificationRankingUpdate update) {
mRanking = new Ranking(update);
mRankingMap = new RankingMap(update);
}
/**
* Provides access to ranking information on a currently active
* notification.
*
* <p>
* Note that this object is not updated on notification events (such as
* {@link #onNotificationPosted(StatusBarNotification, RankingMap)},
* {@link #onNotificationRemoved(StatusBarNotification)}, etc.). Make sure
* to retrieve a new Ranking from the current {@link RankingMap} whenever
* a notification event occurs.
*/
public static class Ranking {
private final String mKey;
private final int mRank;
private final boolean mIsAmbient;
private final boolean mIsInterceptedByDnd;
private Ranking(String key, int rank, boolean isAmbient, boolean isInterceptedByDnd) {
mKey = key;
mRank = rank;
mIsAmbient = isAmbient;
mIsInterceptedByDnd = isInterceptedByDnd;
}
/**
* Returns the key of the notification this Ranking applies to.
*/
public String getKey() {
return mKey;
}
/**
* Returns the rank of the notification.
*
* @return the rank of the notification, that is the 0-based index in
* the list of active notifications.
*/
public int getRank() {
return mRank;
}
/**
* Returns whether the notification is an ambient notification, that is
* a notification that doesn't require the user's immediate attention.
*/
public boolean isAmbient() {
return mIsAmbient;
}
/**
* Returns whether the notification was intercepted by
* &quot;Do not disturb&quot;.
*/
public boolean isInterceptedByDoNotDisturb() {
return mIsInterceptedByDnd;
}
}
/**
@@ -371,11 +475,14 @@ public abstract class NotificationListenerService extends Service {
* Note that this object represents a ranking snapshot that only applies to
* notifications active at the time of retrieval.
*/
public static class Ranking implements Parcelable {
public static class RankingMap implements Parcelable {
private final NotificationRankingUpdate mRankingUpdate;
private final ArrayMap<String, Ranking> mRankingCache;
private boolean mRankingCacheInitialized;
private Ranking(NotificationRankingUpdate rankingUpdate) {
private RankingMap(NotificationRankingUpdate rankingUpdate) {
mRankingUpdate = rankingUpdate;
mRankingCache = new ArrayMap<>(rankingUpdate.getOrderedKeys().length);
}
/**
@@ -389,56 +496,37 @@ public abstract class NotificationListenerService extends Service {
}
/**
* Returns the rank of the notification with the given key, that is the
* index of <code>key</code> in the array of keys returned by
* {@link #getOrderedKeys()}.
* Returns the Ranking for the notification with the given key.
*
* @return The rank of the notification with the given key; -1 when the
* given key is unknown.
* @return the Ranking of the notification with the given key;
* <code>null</code> when the key is unknown.
*/
public int getRank(String key) {
// TODO: Optimize.
public Ranking getRanking(String key) {
synchronized (mRankingCache) {
if (!mRankingCacheInitialized) {
initializeRankingCache();
mRankingCacheInitialized = true;
}
}
return mRankingCache.get(key);
}
private void initializeRankingCache() {
String[] orderedKeys = mRankingUpdate.getOrderedKeys();
for (int i = 0; i < orderedKeys.length; i++) {
if (orderedKeys[i].equals(key)) {
return i;
}
}
return -1;
}
/**
* Returns whether the notification with the given key was intercepted
* by &quot;Do not disturb&quot;.
*/
public boolean isInterceptedByDoNotDisturb(String key) {
// TODO: Optimize.
for (String interceptedKey : mRankingUpdate.getDndInterceptedKeys()) {
if (interceptedKey.equals(key)) {
return true;
}
}
return false;
}
/**
* Returns whether the notification with the given key is an ambient
* notification, that is a notification that doesn't require the user's
* immediate attention.
*/
public boolean isAmbient(String key) {
// TODO: Optimize.
int firstAmbientIndex = mRankingUpdate.getFirstAmbientIndex();
if (firstAmbientIndex < 0) {
return false;
}
String[] orderedKeys = mRankingUpdate.getOrderedKeys();
for (int i = firstAmbientIndex; i < orderedKeys.length; i++) {
if (orderedKeys[i].equals(key)) {
return true;
for (int i = 0; i < orderedKeys.length; i++) {
String key = orderedKeys[i];
boolean isAmbient = firstAmbientIndex > -1 && firstAmbientIndex <= i;
boolean isInterceptedByDnd = false;
// TODO: Optimize.
for (String s : mRankingUpdate.getDndInterceptedKeys()) {
if (s.equals(key)) {
isInterceptedByDnd = true;
break;
}
}
mRankingCache.put(key, new Ranking(key, i, isAmbient, isInterceptedByDnd));
}
return false;
}
// ----------- Parcelable
@@ -453,16 +541,16 @@ public abstract class NotificationListenerService extends Service {
dest.writeParcelable(mRankingUpdate, flags);
}
public static final Creator<Ranking> CREATOR = new Creator<Ranking>() {
public static final Creator<RankingMap> CREATOR = new Creator<RankingMap>() {
@Override
public Ranking createFromParcel(Parcel source) {
public RankingMap createFromParcel(Parcel source) {
NotificationRankingUpdate rankingUpdate = source.readParcelable(null);
return new Ranking(rankingUpdate);
return new RankingMap(rankingUpdate);
}
@Override
public Ranking[] newArray(int size) {
return new Ranking[size];
public RankingMap[] newArray(int size) {
return new RankingMap[size];
}
};
}

View File

@@ -48,7 +48,7 @@ import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
@@ -293,7 +293,7 @@ public abstract class BaseStatusBar extends SystemUI implements
public void onListenerConnected() {
if (DEBUG) Log.d(TAG, "onListenerConnected");
final StatusBarNotification[] notifications = getActiveNotifications();
final Ranking currentRanking = getCurrentRanking();
final RankingMap currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -305,41 +305,40 @@ public abstract class BaseStatusBar extends SystemUI implements
}
@Override
public void onNotificationPosted(final StatusBarNotification sbn) {
public void onNotificationPosted(final StatusBarNotification sbn,
final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
final Ranking currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
if (mNotificationData.findByKey(sbn.getKey()) != null) {
updateNotificationInternal(sbn, currentRanking);
updateNotificationInternal(sbn, rankingMap);
} else {
addNotificationInternal(sbn, currentRanking);
addNotificationInternal(sbn, rankingMap);
}
}
});
}
@Override
public void onNotificationRemoved(final StatusBarNotification sbn) {
public void onNotificationRemoved(final StatusBarNotification sbn,
final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
final Ranking currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
removeNotificationInternal(sbn.getKey(), currentRanking);
removeNotificationInternal(sbn.getKey(), rankingMap);
}
});
}
@Override
public void onNotificationRankingUpdate() {
public void onNotificationRankingUpdate(final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onRankingUpdate");
final Ranking currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
updateRankingInternal(currentRanking);
updateRankingInternal(rankingMap);
}
});
}
@@ -1177,7 +1176,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
protected StatusBarNotification removeNotificationViews(String key, Ranking ranking) {
protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
NotificationData.Entry entry = mNotificationData.remove(key, ranking);
if (entry == null) {
Log.w(TAG, "removeNotification for unknown key: " + key);
@@ -1217,7 +1216,7 @@ public abstract class BaseStatusBar extends SystemUI implements
return entry;
}
protected void addNotificationViews(Entry entry, Ranking ranking) {
protected void addNotificationViews(Entry entry, RankingMap ranking) {
if (entry == null) {
return;
}
@@ -1226,7 +1225,7 @@ public abstract class BaseStatusBar extends SystemUI implements
updateNotifications();
}
private void addNotificationViews(StatusBarNotification notification, Ranking ranking) {
private void addNotificationViews(StatusBarNotification notification, RankingMap ranking) {
addNotificationViews(createNotificationViews(notification), ranking);
}
@@ -1312,9 +1311,9 @@ public abstract class BaseStatusBar extends SystemUI implements
}
public abstract void addNotificationInternal(StatusBarNotification notification,
Ranking ranking);
RankingMap ranking);
protected abstract void updateRankingInternal(Ranking ranking);
protected abstract void updateRankingInternal(RankingMap ranking);
@Override
public void removeNotification(String key) {
@@ -1323,7 +1322,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
public abstract void removeNotificationInternal(String key, Ranking ranking);
public abstract void removeNotificationInternal(String key, RankingMap ranking);
public void updateNotification(StatusBarNotification notification) {
if (!USE_NOTIFICATION_LISTENER) {
@@ -1331,7 +1330,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
public void updateNotificationInternal(StatusBarNotification notification, Ranking ranking) {
public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
final NotificationData.Entry oldEntry = mNotificationData.findByKey(notification.getKey());

View File

@@ -21,6 +21,7 @@ import android.content.Context;
import android.os.Process;
import android.provider.Settings;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -58,17 +59,18 @@ public class InterceptedNotifications {
updateSyntheticNotification();
}
public boolean tryIntercept(StatusBarNotification notification, Ranking ranking) {
if (ranking == null) return false;
public boolean tryIntercept(StatusBarNotification notification, RankingMap rankingMap) {
if (rankingMap == null) return false;
if (shouldDisplayIntercepted()) return false;
if (mReleased.contains(notification.getKey())) return false;
if (!ranking.isInterceptedByDoNotDisturb(notification.getKey())) return false;
Ranking ranking = rankingMap.getRanking(notification.getKey());
if (!ranking.isInterceptedByDoNotDisturb()) return false;
mIntercepted.put(notification.getKey(), notification);
updateSyntheticNotification();
return true;
}
public void retryIntercepts(Ranking ranking) {
public void retryIntercepts(RankingMap ranking) {
if (ranking == null) return;
final int N = mIntercepted.size();

View File

@@ -18,6 +18,7 @@ package com.android.systemui.statusbar;
import android.app.Notification;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.view.View;
@@ -70,12 +71,16 @@ public class NotificationData {
}
private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
private Ranking mRanking;
private RankingMap mRanking;
private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
@Override
public int compare(Entry a, Entry b) {
if (mRanking != null) {
return mRanking.getRank(a.key) - mRanking.getRank(b.key);
Ranking aRanking = mRanking.getRanking(a.key);
Ranking bRanking = mRanking.getRanking(b.key);
int aRank = aRanking != null ? aRanking.getRank() : -1;
int bRank = bRanking != null ? bRanking.getRank() : -1;
return aRank - bRank;
}
final StatusBarNotification na = a.notification;
@@ -108,12 +113,12 @@ public class NotificationData {
return null;
}
public void add(Entry entry, Ranking ranking) {
public void add(Entry entry, RankingMap ranking) {
mEntries.add(entry);
updateRankingAndSort(ranking);
}
public Entry remove(String key, Ranking ranking) {
public Entry remove(String key, RankingMap ranking) {
Entry e = findByKey(key);
if (e == null) {
return null;
@@ -123,7 +128,7 @@ public class NotificationData {
return e;
}
public void updateRanking(Ranking ranking) {
public void updateRanking(RankingMap ranking) {
updateRankingAndSort(ranking);
}
@@ -137,12 +142,13 @@ public class NotificationData {
}
}
} else {
return mRanking.isAmbient(key);
Ranking ranking = mRanking.getRanking(key);
return ranking != null && ranking.isAmbient();
}
return false;
}
private void updateRankingAndSort(Ranking ranking) {
private void updateRankingAndSort(RankingMap ranking) {
if (ranking != null) {
mRanking = ranking;
}

View File

@@ -64,7 +64,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.DisplayMetrics;
@@ -1051,7 +1051,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
public void addNotificationInternal(StatusBarNotification notification, Ranking ranking) {
public void addNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(notification, ranking)) {
// Forward the ranking so we can sort the new notification.
@@ -1062,8 +1062,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
displayNotification(notification, ranking);
}
public void displayNotification(StatusBarNotification notification,
Ranking ranking) {
public void displayNotification(StatusBarNotification notification, RankingMap ranking) {
if (mUseHeadsUp && shouldInterrupt(notification)) {
if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
Entry interruptionCandidate = new Entry(notification, null);
@@ -1147,21 +1146,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
public void updateNotificationInternal(StatusBarNotification notification, Ranking ranking) {
public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
super.updateNotificationInternal(notification, ranking);
// if we're here, then the notification is already in the shade
mIntercepted.remove(notification.getKey());
}
@Override
protected void updateRankingInternal(Ranking ranking) {
protected void updateRankingInternal(RankingMap ranking) {
mNotificationData.updateRanking(ranking);
mIntercepted.retryIntercepts(ranking);
updateNotifications();
}
@Override
public void removeNotificationInternal(String key, Ranking ranking) {
public void removeNotificationInternal(String key, RankingMap ranking) {
if (ENABLE_HEADS_UP && mHeadsUpNotificationView.getEntry() != null
&& key.equals(mHeadsUpNotificationView.getEntry().notification.getKey())) {
mHeadsUpNotificationView.clear();

View File

@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.tv;
import android.os.IBinder;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
@@ -51,11 +51,11 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
public void addNotificationInternal(StatusBarNotification notification, Ranking ranking) {
public void addNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
}
@Override
protected void updateRankingInternal(Ranking ranking) {
protected void updateRankingInternal(RankingMap ranking) {
}
@Override
@@ -63,7 +63,7 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
public void removeNotificationInternal(String key, Ranking ranking) {
public void removeNotificationInternal(String key, RankingMap ranking) {
}
@Override