NotificationListenerService API: Avoid unnecessary allocations
Instead of producing Ranking objects, RankingMap just populates
them now, allowing developers to re-use objects and avoid
unnecessary allocations.
Also rename isInterceptedByDnd() to meetsInterruptionFilter(),
since DND is not a concept anymore.
Bug: 15415840
Bug: 16099064
Change-Id: If9861cbdf14593e641a4d4ffd1b967647eb8e2b8
diff --git a/api/current.txt b/api/current.txt
index 9d43d58..38e0320 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26336,16 +26336,17 @@
}
public static class NotificationListenerService.Ranking {
+ ctor public NotificationListenerService.Ranking();
method public java.lang.String getKey();
method public int getRank();
method public boolean isAmbient();
- method public boolean isInterceptedByDoNotDisturb();
+ method public boolean meetsInterruptionFilter();
}
public static class NotificationListenerService.RankingMap implements android.os.Parcelable {
method public int describeContents();
method public java.lang.String[] getOrderedKeys();
- method public android.service.notification.NotificationListenerService.Ranking getRanking(java.lang.String);
+ method public boolean getRanking(java.lang.String, android.service.notification.NotificationListenerService.Ranking);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 8bd0f4d..7d5ff33 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -29,7 +29,6 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.util.ArrayMap;
import android.util.Log;
import java.util.List;
@@ -410,28 +409,20 @@
}
/**
- * Provides access to ranking information on a currently active
- * notification.
+ * Stores ranking related 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.
+ * Ranking objects aren't automatically updated as notification events
+ * occur. Instead, ranking information has to be retrieved again via the
+ * current {@link RankingMap}.
*/
public static class Ranking {
- private final String mKey;
- private final int mRank;
- private final boolean mIsAmbient;
- private final boolean mIsInterceptedByDnd;
+ private String mKey;
+ private int mRank = -1;
+ private boolean mIsAmbient;
+ private boolean mMeetsInterruptionFilter;
- private Ranking(String key, int rank, boolean isAmbient, boolean isInterceptedByDnd) {
- mKey = key;
- mRank = rank;
- mIsAmbient = isAmbient;
- mIsInterceptedByDnd = isInterceptedByDnd;
- }
+ public Ranking() {}
/**
* Returns the key of the notification this Ranking applies to.
@@ -459,11 +450,19 @@
}
/**
- * Returns whether the notification was intercepted by
- * "Do not disturb".
+ * Returns whether the notification meets the user's interruption
+ * filter.
*/
- public boolean isInterceptedByDoNotDisturb() {
- return mIsInterceptedByDnd;
+ public boolean meetsInterruptionFilter() {
+ return mMeetsInterruptionFilter;
+ }
+
+ private void populate(String key, int rank, boolean isAmbient,
+ boolean meetsInterruptionFilter) {
+ mKey = key;
+ mRank = rank;
+ mIsAmbient = isAmbient;
+ mMeetsInterruptionFilter = meetsInterruptionFilter;
}
}
@@ -477,12 +476,9 @@
*/
public static class RankingMap implements Parcelable {
private final NotificationRankingUpdate mRankingUpdate;
- private final ArrayMap<String, Ranking> mRankingCache;
- private boolean mRankingCacheInitialized;
private RankingMap(NotificationRankingUpdate rankingUpdate) {
mRankingUpdate = rankingUpdate;
- mRankingCache = new ArrayMap<>(rankingUpdate.getOrderedKeys().length);
}
/**
@@ -496,37 +492,42 @@
}
/**
- * Returns the Ranking for the notification with the given key.
+ * Populates outRanking with ranking information for the notification
+ * with the given key.
*
- * @return the Ranking of the notification with the given key;
- * <code>null</code> when the key is unknown.
+ * @return true if a valid key has been passed and outRanking has
+ * been populated; false otherwise
*/
- public Ranking getRanking(String key) {
- synchronized (mRankingCache) {
- if (!mRankingCacheInitialized) {
- initializeRankingCache();
- mRankingCacheInitialized = true;
- }
- }
- return mRankingCache.get(key);
+ public boolean getRanking(String key, Ranking outRanking) {
+ int rank = getRank(key);
+ outRanking.populate(key, rank, isAmbient(key), !isIntercepted(key));
+ return rank >= 0;
}
- private void initializeRankingCache() {
+ private int getRank(String key) {
+ // TODO: Optimize.
String[] orderedKeys = mRankingUpdate.getOrderedKeys();
- int firstAmbientIndex = mRankingUpdate.getFirstAmbientIndex();
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;
- }
+ if (orderedKeys[i].equals(key)) {
+ return i;
}
- mRankingCache.put(key, new Ranking(key, i, isAmbient, isInterceptedByDnd));
}
+ return -1;
+ }
+
+ private boolean isAmbient(String key) {
+ int rank = getRank(key);
+ return rank >= 0 && rank >= mRankingUpdate.getFirstAmbientIndex();
+ }
+
+ private boolean isIntercepted(String key) {
+ // TODO: Optimize.
+ for (String interceptedKey : mRankingUpdate.getInterceptedKeys()) {
+ if (interceptedKey.equals(key)) {
+ return true;
+ }
+ }
+ return false;
}
// ----------- Parcelable
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index 4b13d95..26af38b 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -24,20 +24,20 @@
public class NotificationRankingUpdate implements Parcelable {
// TODO: Support incremental updates.
private final String[] mKeys;
- private final String[] mDndInterceptedKeys;
+ private final String[] mInterceptedKeys;
private final int mFirstAmbientIndex;
- public NotificationRankingUpdate(String[] keys, String[] dndInterceptedKeys,
+ public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
int firstAmbientIndex) {
mKeys = keys;
mFirstAmbientIndex = firstAmbientIndex;
- mDndInterceptedKeys = dndInterceptedKeys;
+ mInterceptedKeys = interceptedKeys;
}
public NotificationRankingUpdate(Parcel in) {
mKeys = in.readStringArray();
mFirstAmbientIndex = in.readInt();
- mDndInterceptedKeys = in.readStringArray();
+ mInterceptedKeys = in.readStringArray();
}
@Override
@@ -49,7 +49,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeStringArray(mKeys);
out.writeInt(mFirstAmbientIndex);
- out.writeStringArray(mDndInterceptedKeys);
+ out.writeStringArray(mInterceptedKeys);
}
public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -71,7 +71,7 @@
return mFirstAmbientIndex;
}
- public String[] getDndInterceptedKeys() {
- return mDndInterceptedKeys;
+ public String[] getInterceptedKeys() {
+ return mInterceptedKeys;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 9921c55..ed3ebf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -75,16 +75,18 @@
}
private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
- private RankingMap mRanking;
+ private RankingMap mRankingMap;
+ private final Ranking mTmpRanking = new Ranking();
private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
+ private final Ranking mRankingA = new Ranking();
+ private final Ranking mRankingB = new Ranking();
+
@Override
public int compare(Entry a, Entry b) {
- if (mRanking != null) {
- 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;
+ if (mRankingMap != null) {
+ mRankingMap.getRanking(a.key, mRankingA);
+ mRankingMap.getRanking(b.key, mRankingB);
+ return mRankingA.getRank() - mRankingB.getRank();
}
final StatusBarNotification na = a.notification;
@@ -138,7 +140,7 @@
public boolean isAmbient(String key) {
// TODO: Remove when switching to NotificationListener.
- if (mRanking == null) {
+ if (mRankingMap == null) {
for (Entry entry : mEntries) {
if (key.equals(entry.key)) {
return entry.notification.getNotification().priority ==
@@ -146,15 +148,15 @@
}
}
} else {
- Ranking ranking = mRanking.getRanking(key);
- return ranking != null && ranking.isAmbient();
+ mRankingMap.getRanking(key, mTmpRanking);
+ return mTmpRanking.isAmbient();
}
return false;
}
private void updateRankingAndSort(RankingMap ranking) {
if (ranking != null) {
- mRanking = ranking;
+ mRankingMap = ranking;
}
Collections.sort(mEntries, mRankingComparator);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3a6cec2..892f61f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2301,7 +2301,7 @@
int speedBumpIndex = -1;
final int N = mNotificationList.size();
ArrayList<String> keys = new ArrayList<String>(N);
- ArrayList<String> dndKeys = new ArrayList<String>(N);
+ ArrayList<String> interceptedKeys = new ArrayList<String>(N);
for (int i = 0; i < N; i++) {
NotificationRecord record = mNotificationList.get(i);
if (!info.enabledAndUserMatches(record.sbn.getUserId())) {
@@ -2309,7 +2309,7 @@
}
keys.add(record.sbn.getKey());
if (record.isIntercepted()) {
- dndKeys.add(record.sbn.getKey());
+ interceptedKeys.add(record.sbn.getKey());
}
if (speedBumpIndex == -1 &&
record.sbn.getNotification().priority == Notification.PRIORITY_MIN) {
@@ -2317,8 +2317,8 @@
}
}
String[] keysAr = keys.toArray(new String[keys.size()]);
- String[] dndKeysAr = dndKeys.toArray(new String[dndKeys.size()]);
- return new NotificationRankingUpdate(keysAr, dndKeysAr, speedBumpIndex);
+ String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
+ return new NotificationRankingUpdate(keysAr, interceptedKeysAr, speedBumpIndex);
}
public class NotificationListeners extends ManagedServices {