Merge "Stop populating RemoteViews in Notifications."

This commit is contained in:
Julia Reynolds
2015-10-27 20:36:31 +00:00
committed by Android (Google) Code Review
8 changed files with 539 additions and 851 deletions

View File

@@ -4830,17 +4830,17 @@ package android.app {
field public android.app.Notification.Action[] actions;
field public android.media.AudioAttributes audioAttributes;
field public deprecated int audioStreamType;
field public android.widget.RemoteViews bigContentView;
field public deprecated android.widget.RemoteViews bigContentView;
field public java.lang.String category;
field public int color;
field public android.app.PendingIntent contentIntent;
field public android.widget.RemoteViews contentView;
field public deprecated android.widget.RemoteViews contentView;
field public int defaults;
field public android.app.PendingIntent deleteIntent;
field public android.os.Bundle extras;
field public int flags;
field public android.app.PendingIntent fullScreenIntent;
field public android.widget.RemoteViews headsUpContentView;
field public deprecated android.widget.RemoteViews headsUpContentView;
field public deprecated int icon;
field public int iconLevel;
field public deprecated android.graphics.Bitmap largeIcon;
@@ -4931,14 +4931,22 @@ package android.app {
method public android.app.Notification.Builder extend(android.app.Notification.Extender);
method public android.os.Bundle getExtras();
method public deprecated android.app.Notification getNotification();
method public android.widget.RemoteViews makeBigContentView();
method public android.widget.RemoteViews makeContentView();
method public android.widget.RemoteViews makeHeadsUpContentView();
method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
method public android.app.Notification.Builder setAutoCancel(boolean);
method public android.app.Notification.Builder setCategory(java.lang.String);
method public android.app.Notification.Builder setColor(int);
method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setContentText(java.lang.CharSequence);
method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence);
method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setDefaults(int);
method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setExtras(android.os.Bundle);

View File

@@ -4947,17 +4947,17 @@ package android.app {
field public android.app.Notification.Action[] actions;
field public android.media.AudioAttributes audioAttributes;
field public deprecated int audioStreamType;
field public android.widget.RemoteViews bigContentView;
field public deprecated android.widget.RemoteViews bigContentView;
field public java.lang.String category;
field public int color;
field public android.app.PendingIntent contentIntent;
field public android.widget.RemoteViews contentView;
field public deprecated android.widget.RemoteViews contentView;
field public int defaults;
field public android.app.PendingIntent deleteIntent;
field public android.os.Bundle extras;
field public int flags;
field public android.app.PendingIntent fullScreenIntent;
field public android.widget.RemoteViews headsUpContentView;
field public deprecated android.widget.RemoteViews headsUpContentView;
field public deprecated int icon;
field public int iconLevel;
field public deprecated android.graphics.Bitmap largeIcon;
@@ -5048,14 +5048,22 @@ package android.app {
method public android.app.Notification.Builder extend(android.app.Notification.Extender);
method public android.os.Bundle getExtras();
method public deprecated android.app.Notification getNotification();
method public android.widget.RemoteViews makeBigContentView();
method public android.widget.RemoteViews makeContentView();
method public android.widget.RemoteViews makeHeadsUpContentView();
method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
method public android.app.Notification.Builder setAutoCancel(boolean);
method public android.app.Notification.Builder setCategory(java.lang.String);
method public android.app.Notification.Builder setColor(int);
method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setContentText(java.lang.CharSequence);
method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence);
method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
method public android.app.Notification.Builder setDefaults(int);
method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setExtras(android.os.Bundle);

File diff suppressed because it is too large Load Diff

View File

@@ -207,33 +207,7 @@ public class NotificationManager
*/
public void notify(String tag, int id, Notification notification)
{
int[] idOut = new int[1];
INotificationManager service = getService();
String pkg = mContext.getPackageName();
if (notification.sound != null) {
notification.sound = notification.sound.getCanonicalUri();
if (StrictMode.vmFileUriExposureEnabled()) {
notification.sound.checkFileUriExposed("Notification.sound");
}
}
fixLegacySmallIcon(notification, pkg);
if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
if (notification.getSmallIcon() == null) {
throw new IllegalArgumentException("Invalid notification (no valid small icon): "
+ notification);
}
}
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
Notification stripped = notification.clone();
Builder.stripForDelivery(stripped);
try {
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
stripped, idOut, UserHandle.myUserId());
if (id != idOut[0]) {
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
}
} catch (RemoteException e) {
}
notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));
}
/**
@@ -251,12 +225,17 @@ public class NotificationManager
}
}
fixLegacySmallIcon(notification, pkg);
if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
if (notification.getSmallIcon() == null) {
throw new IllegalArgumentException("Invalid notification (no valid small icon): "
+ notification);
}
}
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
Notification stripped = notification.clone();
Builder.stripForDelivery(stripped);
final Notification copy = notification.clone();
try {
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
stripped, idOut, user.getIdentifier());
copy, idOut, user.getIdentifier());
if (id != idOut[0]) {
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
}
@@ -287,13 +266,7 @@ public class NotificationManager
*/
public void cancel(String tag, int id)
{
INotificationManager service = getService();
String pkg = mContext.getPackageName();
if (localLOGV) Log.v(TAG, pkg + ": cancel(" + id + ")");
try {
service.cancelNotificationWithTag(pkg, tag, id, UserHandle.myUserId());
} catch (RemoteException e) {
}
cancelAsUser(tag, id, new UserHandle(UserHandle.myUserId()));
}
/**

View File

@@ -31,6 +31,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
@@ -472,9 +473,10 @@ public abstract class NotificationListenerService extends Service {
StatusBarNotification sbn = list.get(i);
Notification notification = sbn.getNotification();
try {
Builder.rebuild(getContext(), notification);
// convert icon metadata to legacy format for older clients
createLegacyIconExtras(notification);
// populate remote views for older clients.
maybePopulateRemoteViews(notification);
} catch (IllegalArgumentException e) {
if (corruptNotifications == null) {
corruptNotifications = new ArrayList<>(N);
@@ -676,6 +678,18 @@ public abstract class NotificationListenerService extends Service {
}
}
/**
* Populates remote views for pre-N targeting apps.
*/
private void maybePopulateRemoteViews(Notification notification) {
if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
Builder builder = Builder.recoverBuilder(getContext(), notification);
notification.contentView = builder.makeContentView();
notification.bigContentView = builder.makeBigContentView();
notification.headsUpContentView = builder.makeHeadsUpContentView();
}
}
private class INotificationListenerWrapper extends INotificationListener.Stub {
@Override
public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
@@ -689,9 +703,10 @@ public abstract class NotificationListenerService extends Service {
}
try {
Notification.Builder.rebuild(getContext(), sbn.getNotification());
Notification notification = sbn.getNotification();
// convert icon metadata to legacy format for older clients
createLegacyIconExtras(sbn.getNotification());
maybePopulateRemoteViews(sbn.getNotification());
} catch (IllegalArgumentException e) {
// drop corrupt notification
sbn = null;

View File

@@ -1275,20 +1275,22 @@ public abstract class BaseStatusBar extends SystemUI implements
int maxHeight = mRowMaxHeight;
final StatusBarNotification sbn = entry.notification;
RemoteViews contentView = sbn.getNotification().contentView;
RemoteViews bigContentView = sbn.getNotification().bigContentView;
RemoteViews headsUpContentView = sbn.getNotification().headsUpContentView;
entry.cacheContentViews(mContext, null);
final RemoteViews contentView = entry.cachedContentView;
final RemoteViews bigContentView = entry.cachedBigContentView;
final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
final RemoteViews publicContentView = entry.cachedPublicContentView;
if (contentView == null) {
Log.v(TAG, "no contentView for: " + sbn.getNotification());
return false;
}
if (DEBUG) {
Log.v(TAG, "publicNotification: " + sbn.getNotification().publicVersion);
Log.v(TAG, "publicContentView: " + publicContentView);
}
Notification publicNotification = sbn.getNotification().publicVersion;
ExpandableNotificationRow row;
// Stash away previous user expansion state so we can restore it at
@@ -1377,9 +1379,9 @@ public abstract class BaseStatusBar extends SystemUI implements
// now the public version
View publicViewLocal = null;
if (publicNotification != null) {
if (publicContentView != null) {
try {
publicViewLocal = publicNotification.contentView.apply(
publicViewLocal = publicContentView.apply(
sbn.getPackageContext(mContext),
contentContainerPublic, mOnClickHandler);
@@ -1537,30 +1539,9 @@ public abstract class BaseStatusBar extends SystemUI implements
}
if (viableAction != null) {
Notification stripped = n.clone();
Notification.Builder.stripForDelivery(stripped);
stripped.extras.putBoolean("android.rebuild", true);
stripped.actions = new Notification.Action[] { viableAction };
stripped.extras.putBoolean("android.rebuild.contentView", true);
stripped.contentView = null;
stripped.extras.putBoolean("android.rebuild.bigView", true);
stripped.bigContentView = null;
stripped.extras.putBoolean("android.rebuild.hudView", true);
stripped.headsUpContentView = null;
stripped.extras.putParcelable(Notification.EXTRA_LARGE_ICON,
stripped.getLargeIcon());
if (SystemProperties.getBoolean("debug.strip_third_line", false)) {
stripped.extras.putCharSequence(Notification.EXTRA_INFO_TEXT, null);
stripped.extras.putCharSequence(Notification.EXTRA_SUMMARY_TEXT, null);
}
Notification rebuilt = Notification.Builder.rebuild(mContext, stripped);
n.actions = rebuilt.actions;
n.bigContentView = rebuilt.bigContentView;
n.headsUpContentView = rebuilt.headsUpContentView;
n.publicVersion = rebuilt.publicVersion;
Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
rebuilder.setActions(viableAction);
rebuilder.build(); // will rewrite n
}
}
}
@@ -2034,12 +2015,15 @@ public abstract class BaseStatusBar extends SystemUI implements
}
Notification n = notification.getNotification();
if (DEBUG) {
logUpdate(entry, n);
}
boolean applyInPlace = shouldApplyInPlace(entry, n);
boolean applyInPlace = !entry.cacheContentViews(mContext, notification.getNotification());
boolean shouldInterrupt = shouldInterrupt(entry, notification);
boolean alertAgain = alertAgain(entry, n);
if (DEBUG) {
Log.d(TAG, "applyInPlace=" + applyInPlace
+ " shouldInterrupt=" + shouldInterrupt
+ " alertAgain=" + alertAgain);
}
entry.notification = notification;
mGroupManager.onEntryUpdated(entry, entry.notification);
@@ -2104,101 +2088,32 @@ public abstract class BaseStatusBar extends SystemUI implements
protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldInterrupt,
boolean alertAgain);
private void logUpdate(Entry oldEntry, Notification n) {
StatusBarNotification oldNotification = oldEntry.notification;
Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when
+ " ongoing=" + oldNotification.isOngoing()
+ " expanded=" + oldEntry.getContentView()
+ " contentView=" + oldNotification.getNotification().contentView
+ " bigContentView=" + oldNotification.getNotification().bigContentView
+ " publicView=" + oldNotification.getNotification().publicVersion
+ " rowParent=" + oldEntry.row.getParent());
Log.d(TAG, "new notification: when=" + n.when
+ " ongoing=" + oldNotification.isOngoing()
+ " contentView=" + n.contentView
+ " bigContentView=" + n.bigContentView
+ " publicView=" + n.publicVersion);
}
/**
* @return whether we can just reapply the RemoteViews from a notification in-place when it is
* updated
*/
private boolean shouldApplyInPlace(Entry entry, Notification n) {
StatusBarNotification oldNotification = entry.notification;
// XXX: modify when we do something more intelligent with the two content views
final RemoteViews oldContentView = oldNotification.getNotification().contentView;
final RemoteViews contentView = n.contentView;
final RemoteViews oldBigContentView = oldNotification.getNotification().bigContentView;
final RemoteViews bigContentView = n.bigContentView;
final RemoteViews oldHeadsUpContentView
= oldNotification.getNotification().headsUpContentView;
final RemoteViews headsUpContentView = n.headsUpContentView;
final Notification oldPublicNotification = oldNotification.getNotification().publicVersion;
final RemoteViews oldPublicContentView = oldPublicNotification != null
? oldPublicNotification.contentView : null;
final Notification publicNotification = n.publicVersion;
final RemoteViews publicContentView = publicNotification != null
? publicNotification.contentView : null;
boolean contentsUnchanged = entry.getContentView() != null
&& contentView.getPackage() != null
&& oldContentView.getPackage() != null
&& oldContentView.getPackage().equals(contentView.getPackage())
&& oldContentView.getLayoutId() == contentView.getLayoutId();
// large view may be null
boolean bigContentsUnchanged =
(entry.getExpandedContentView() == null && bigContentView == null)
|| ((entry.getExpandedContentView() != null && bigContentView != null)
&& bigContentView.getPackage() != null
&& oldBigContentView.getPackage() != null
&& oldBigContentView.getPackage().equals(bigContentView.getPackage())
&& oldBigContentView.getLayoutId() == bigContentView.getLayoutId());
boolean headsUpContentsUnchanged =
(oldHeadsUpContentView == null && headsUpContentView == null)
|| ((oldHeadsUpContentView != null && headsUpContentView != null)
&& headsUpContentView.getPackage() != null
&& oldHeadsUpContentView.getPackage() != null
&& oldHeadsUpContentView.getPackage().equals(headsUpContentView.getPackage())
&& oldHeadsUpContentView.getLayoutId() == headsUpContentView.getLayoutId());
boolean publicUnchanged =
(oldPublicContentView == null && publicContentView == null)
|| ((oldPublicContentView != null && publicContentView != null)
&& publicContentView.getPackage() != null
&& oldPublicContentView.getPackage() != null
&& oldPublicContentView.getPackage().equals(publicContentView.getPackage())
&& oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
return contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
&& publicUnchanged;
}
private void updateNotificationViews(Entry entry, StatusBarNotification notification) {
final RemoteViews contentView = notification.getNotification().contentView;
final RemoteViews bigContentView = notification.getNotification().bigContentView;
final RemoteViews headsUpContentView = notification.getNotification().headsUpContentView;
final Notification publicVersion = notification.getNotification().publicVersion;
final RemoteViews publicContentView = publicVersion != null ? publicVersion.contentView
: null;
private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
final RemoteViews contentView = entry.cachedContentView;
final RemoteViews bigContentView = entry.cachedBigContentView;
final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
final RemoteViews publicContentView = entry.cachedPublicContentView;
// Reapply the RemoteViews
contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
if (bigContentView != null && entry.getExpandedContentView() != null) {
bigContentView.reapply(notification.getPackageContext(mContext),
bigContentView.reapply(sbn.getPackageContext(mContext),
entry.getExpandedContentView(),
mOnClickHandler);
}
View headsUpChild = entry.getHeadsUpContentView();
if (headsUpContentView != null && headsUpChild != null) {
headsUpContentView.reapply(notification.getPackageContext(mContext),
headsUpContentView.reapply(sbn.getPackageContext(mContext),
headsUpChild, mOnClickHandler);
}
if (publicContentView != null && entry.getPublicContentView() != null) {
publicContentView.reapply(notification.getPackageContext(mContext),
publicContentView.reapply(sbn.getPackageContext(mContext),
entry.getPublicContentView(), mOnClickHandler);
}
// update the contentIntent
mNotificationClicker.register(entry.row, notification);
mNotificationClicker.register(entry.row, sbn);
entry.row.setStatusBarNotification(notification);
entry.row.setStatusBarNotification(sbn);
entry.row.notifyContentUpdated();
entry.row.resetHeight();

View File

@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
import android.app.Notification;
import android.content.Context;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
@@ -24,6 +25,7 @@ import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.view.View;
import android.widget.RemoteViews;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -53,6 +55,10 @@ public class NotificationData {
public boolean legacy; // whether the notification has a legacy, dark background
public int targetSdk;
private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
public RemoteViews cachedContentView;
public RemoteViews cachedBigContentView;
public RemoteViews cachedHeadsUpContentView;
public RemoteViews cachedPublicContentView;
public Entry(StatusBarNotification n, StatusBarIconView ic) {
this.key = n.getKey();
@@ -98,6 +104,67 @@ public class NotificationData {
return row.getPublicLayout().getContractedChild();
}
public boolean cacheContentViews(Context ctx, Notification updatedNotification) {
boolean cached = false;
if (updatedNotification != null) {
final Notification.Builder updatedNotificationBuilder
= Notification.Builder.recoverBuilder(ctx, updatedNotification);
final RemoteViews newContentView = updatedNotificationBuilder.makeContentView();
if (!compareRemoteViews(cachedContentView, newContentView)) {
cachedContentView = newContentView;
cached |= true;
}
final RemoteViews newBigContentView =
updatedNotificationBuilder.makeBigContentView();
if (!compareRemoteViews(cachedBigContentView, newBigContentView)) {
cachedBigContentView = newBigContentView;
cached |= true;
}
final RemoteViews newHeadsUpContentView =
updatedNotificationBuilder.makeHeadsUpContentView();
if (!compareRemoteViews(cachedHeadsUpContentView, newBigContentView)) {
cachedHeadsUpContentView = newHeadsUpContentView;
cached |= true;
}
final Notification updatedPublicNotification = updatedNotification.publicVersion;
final RemoteViews newPubContentView = (updatedPublicNotification != null)
? Notification.Builder.recoverBuilder(
ctx, updatedPublicNotification).makeContentView()
: null;
if (!compareRemoteViews(cachedPublicContentView, newPubContentView)) {
cachedPublicContentView = newPubContentView;
cached |= true;
}
} else {
final Notification.Builder builder
= Notification.Builder.recoverBuilder(ctx, notification.getNotification());
cachedContentView = builder.makeContentView();
cachedBigContentView = builder.makeBigContentView();
cachedHeadsUpContentView = builder.makeHeadsUpContentView();
final Notification publicNotification =
notification.getNotification().publicVersion;
if (publicNotification != null) {
final Notification.Builder publicBuilder
= Notification.Builder.recoverBuilder(ctx, publicNotification);
cachedPublicContentView = publicBuilder.makeContentView();
}
cached = true;
}
return cached;
}
// Returns true if the RemoteViews are the same.
private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
return (a == null && b == null) ||
(a != null && b != null
&& b.getPackage() != null
&& a.getPackage() != null
&& a.getPackage().equals(b.getPackage())
&& a.getLayoutId() == b.getLayoutId());
}
public void notifyFullScreenIntentLaunched() {
lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
}

View File

@@ -2146,13 +2146,6 @@ public class NotificationManagerService extends SystemService {
+ " id=" + id + " notification=" + notification);
}
if (notification.getSmallIcon() != null) {
if (!notification.isValid()) {
throw new IllegalArgumentException("Invalid notification (): pkg=" + pkg
+ " id=" + id + " notification=" + notification);
}
}
mHandler.post(new Runnable() {
@Override
public void run() {