Merge "NoMan: Allow listeners to specify notification trim" into lmp-dev
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 214f50c..fb28c5d 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -58,11 +58,12 @@
void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
- ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys);
+ ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim);
void requestHintsFromListener(in INotificationListener token, int hints);
int getHintsFromListener(in INotificationListener token);
void requestInterruptionFilterFromListener(in INotificationListener token, int interruptionFilter);
int getInterruptionFilterFromListener(in INotificationListener token);
+ void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
ComponentName getEffectsSuppressor();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8a26ba5..966d2ce 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1424,6 +1424,8 @@
extras.remove(Notification.EXTRA_LARGE_ICON);
extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
extras.remove(Notification.EXTRA_PICTURE);
+ // Prevent light notifications from being rebuilt.
+ extras.remove(Builder.EXTRA_NEEDS_REBUILD);
}
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index a544b2d..cb0bcf2 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -81,6 +81,33 @@
* This does not change the interruption filter, only the effects. **/
public static final int HINT_HOST_DISABLE_EFFECTS = 1;
+ /**
+ * The full trim of the StatusBarNotification including all its features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int TRIM_FULL = 0;
+
+ /**
+ * A light trim of the StatusBarNotification excluding the following features:
+ *
+ * <ol>
+ * <li>{@link Notification#tickerView tickerView}</li>
+ * <li>{@link Notification#contentView contentView}</li>
+ * <li>{@link Notification#largeIcon largeIcon}</li>
+ * <li>{@link Notification#bigContentView bigContentView}</li>
+ * <li>{@link Notification#headsUpContentView headsUpContentView}</li>
+ * <li>{@link Notification#EXTRA_LARGE_ICON extras[EXTRA_LARGE_ICON]}</li>
+ * <li>{@link Notification#EXTRA_LARGE_ICON_BIG extras[EXTRA_LARGE_ICON_BIG]}</li>
+ * <li>{@link Notification#EXTRA_PICTURE extras[EXTRA_PICTURE]}</li>
+ * </ol>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int TRIM_LIGHT = 1;
+
private INotificationListenerWrapper mWrapper = null;
private RankingMap mRankingMap;
@@ -314,13 +341,53 @@
}
/**
+ * Sets the notification trim that will be received via {@link #onNotificationPosted}.
+ *
+ * <p>
+ * Setting a trim other than {@link #TRIM_FULL} enables listeners that don't need access to the
+ * full notification features right away to reduce their memory footprint. Full notifications
+ * can be requested on-demand via {@link #getActiveNotifications(int)}.
+ *
+ * <p>
+ * Set to {@link #TRIM_FULL} initially.
+ *
+ * @hide
+ *
+ * @param trim trim of the notifications to be passed via {@link #onNotificationPosted}.
+ * See <code>TRIM_*</code> constants.
+ */
+ @SystemApi
+ public final void setOnNotificationPostedTrim(int trim) {
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().setOnNotificationPostedTrimFromListener(mWrapper, trim);
+ } catch (RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ /**
* Request the list of outstanding notifications (that is, those that are visible to the
* current user). Useful when you don't know what's already been posted.
*
* @return An array of active notifications, sorted in natural order.
*/
public StatusBarNotification[] getActiveNotifications() {
- return getActiveNotifications(null);
+ return getActiveNotifications(null, TRIM_FULL);
+ }
+
+ /**
+ * Request the list of outstanding notifications (that is, those that are visible to the
+ * current user). Useful when you don't know what's already been posted.
+ *
+ * @hide
+ *
+ * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
+ * @return An array of active notifications, sorted in natural order.
+ */
+ @SystemApi
+ public StatusBarNotification[] getActiveNotifications(int trim) {
+ return getActiveNotifications(null, trim);
}
/**
@@ -328,14 +395,33 @@
* notifications but didn't want to retain the bits, and now need to go back and extract
* more data out of those notifications.
*
+ * @param keys the keys of the notifications to request
* @return An array of notifications corresponding to the requested keys, in the
* same order as the key list.
*/
public StatusBarNotification[] getActiveNotifications(String[] keys) {
- if (!isBound()) return null;
+ return getActiveNotifications(keys, TRIM_FULL);
+ }
+
+ /**
+ * Request one or more notifications by key. Useful if you have been keeping track of
+ * notifications but didn't want to retain the bits, and now need to go back and extract
+ * more data out of those notifications.
+ *
+ * @hide
+ *
+ * @param keys the keys of the notifications to request
+ * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
+ * @return An array of notifications corresponding to the requested keys, in the
+ * same order as the key list.
+ */
+ @SystemApi
+ public StatusBarNotification[] getActiveNotifications(String[] keys, int trim) {
+ if (!isBound())
+ return null;
try {
- ParceledListSlice<StatusBarNotification> parceledList =
- getNotificationInterface().getActiveNotificationsFromListener(mWrapper, keys);
+ ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface()
+ .getActiveNotificationsFromListener(mWrapper, keys, trim);
List<StatusBarNotification> list = parceledList.getList();
int N = list.size();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index fc1b746..4101232 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -17,6 +17,8 @@
package com.android.server.notification;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
+import static android.service.notification.NotificationListenerService.TRIM_FULL;
+import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -1290,24 +1292,23 @@
*/
@Override
public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
- INotificationListener token, String[] keys) {
+ INotificationListener token, String[] keys, int trim) {
synchronized (mNotificationList) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
- final ArrayList<StatusBarNotification> list
- = new ArrayList<StatusBarNotification>();
final boolean getKeys = keys != null;
final int N = getKeys ? keys.length : mNotificationList.size();
- list.ensureCapacity(N);
+ final ArrayList<StatusBarNotification> list
+ = new ArrayList<StatusBarNotification>(N);
for (int i=0; i<N; i++) {
final NotificationRecord r = getKeys
? mNotificationsByKey.get(keys[i])
: mNotificationList.get(i);
- if (r != null) {
- StatusBarNotification sbn = r.sbn;
- if (isVisibleToListener(sbn, info)) {
- list.add(sbn);
- }
- }
+ if (r == null) continue;
+ StatusBarNotification sbn = r.sbn;
+ if (!isVisibleToListener(sbn, info)) continue;
+ StatusBarNotification sbnToSend =
+ (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
+ list.add(sbnToSend);
}
return new ParceledListSlice<StatusBarNotification>(list);
}
@@ -1364,6 +1365,16 @@
}
@Override
+ public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
+ throws RemoteException {
+ synchronized (mNotificationList) {
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+ if (info == null) return;
+ mListeners.setOnNotificationPostedTrimLocked(info, trim);
+ }
+ }
+
+ @Override
public ZenModeConfig getZenModeConfig() {
enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
return mZenModeHelper.getConfig();
@@ -2611,6 +2622,8 @@
public class NotificationListeners extends ManagedServices {
+ private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
+
public NotificationListeners() {
super(getContext(), mHandler, mNotificationList, mUserProfiles);
}
@@ -2651,6 +2664,20 @@
if (mListenersDisablingEffects.remove(removed)) {
updateListenerHintsLocked();
}
+ mLightTrimListeners.remove(removed);
+ }
+
+ public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
+ if (trim == TRIM_LIGHT) {
+ mLightTrimListeners.add(info);
+ } else {
+ mLightTrimListeners.remove(info);
+ }
+ }
+
+ public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
+ return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
+
}
/**
@@ -2661,8 +2688,10 @@
* but isn't anymore.
*/
public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
- // make a copy in case changes are made to the underlying Notification object
- final StatusBarNotification sbnClone = sbn.clone();
+ // Lazily initialized snapshots of the notification.
+ StatusBarNotification sbnClone = null;
+ StatusBarNotification sbnCloneLight = null;
+
for (final ManagedServiceInfo info : mServices) {
boolean sbnVisible = isVisibleToListener(sbn, info);
boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
@@ -2684,10 +2713,20 @@
continue;
}
+ final int trim = mListeners.getOnNotificationPostedTrim(info);
+
+ if (trim == TRIM_LIGHT && sbnCloneLight == null) {
+ sbnCloneLight = sbn.cloneLight();
+ } else if (trim == TRIM_FULL && sbnClone == null) {
+ sbnClone = sbn.clone();
+ }
+ final StatusBarNotification sbnToPost =
+ (trim == TRIM_FULL) ? sbnClone : sbnCloneLight;
+
mHandler.post(new Runnable() {
@Override
public void run() {
- notifyPosted(info, sbnClone, update);
+ notifyPosted(info, sbnToPost, update);
}
});
}