diff options
4 files changed, 146 insertions, 18 deletions
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 @@ interface INotificationManager 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 e1dc8bf..dfbf3fb 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1424,6 +1424,8 @@ public class Notification implements Parcelable 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 @@ public abstract class NotificationListenerService extends Service { * 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 @@ public abstract class NotificationListenerService extends Service { } /** + * 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 @@ public abstract class NotificationListenerService extends Service { * 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 @@ public class NotificationManagerService extends SystemService { */ @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 @@ public class NotificationManagerService extends SystemService { } @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 NotificationManagerService extends SystemService { public class NotificationListeners extends ManagedServices { + private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); + public NotificationListeners() { super(getContext(), mHandler, mNotificationList, mUserProfiles); } @@ -2651,6 +2664,20 @@ public class NotificationManagerService extends SystemService { 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 @@ public class NotificationManagerService extends SystemService { * 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 @@ public class NotificationManagerService extends SystemService { 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); } }); } |