Fix concurrency issues when parceling StatusBarNotifications.
Protip: Don't mess with Bundles after you've sent them off
for parceling in an RPC.
Note that this change reduces the payload size of
StatusBarNotification objects received in
onNotificationRemoved() callbacks; it scrubs out the
RemoteViews and Bitmaps just as the NoMan's internal archive
does. [You don't really need that information anyway when
hearing about a removed notification; most likely all you
need are the other slots on StatusBarNotification, but
nulling the whole Notification object breaks a lot of
clients.]
Bug: 8616295
Change-Id: Ic899045f2352b96dcf064d3e9e51dad52629aea3
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8d994c4..2e328b2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -635,11 +635,16 @@
@Override
public Notification clone() {
Notification that = new Notification();
- cloneInto(that);
+ cloneInto(that, true);
return that;
}
- private void cloneInto(Notification that) {
+ /**
+ * Copy all (or if heavy is false, all except Bitmaps and RemoteViews) members
+ * of this into that.
+ * @hide
+ */
+ public void cloneInto(Notification that, boolean heavy) {
that.when = this.when;
that.icon = this.icon;
that.number = this.number;
@@ -652,13 +657,13 @@
if (this.tickerText != null) {
that.tickerText = this.tickerText.toString();
}
- if (this.tickerView != null) {
+ if (heavy && this.tickerView != null) {
that.tickerView = this.tickerView.clone();
}
- if (this.contentView != null) {
+ if (heavy && this.contentView != null) {
that.contentView = this.contentView.clone();
}
- if (this.largeIcon != null) {
+ if (heavy && this.largeIcon != null) {
that.largeIcon = Bitmap.createBitmap(this.largeIcon);
}
that.iconLevel = this.iconLevel;
@@ -690,7 +695,6 @@
if (this.extras != null) {
that.extras = new Bundle(this.extras);
-
}
if (this.actions != null) {
@@ -700,9 +704,30 @@
}
}
- if (this.bigContentView != null) {
+ if (heavy && this.bigContentView != null) {
that.bigContentView = this.bigContentView.clone();
}
+
+ if (!heavy) {
+ that.lightenPayload(); // will clean out extras
+ }
+ }
+
+ /**
+ * Removes heavyweight parts of the Notification object for archival or for sending to
+ * listeners when the full contents are not necessary.
+ * @hide
+ */
+ public final void lightenPayload() {
+ tickerView = null;
+ contentView = null;
+ bigContentView = null;
+ largeIcon = null;
+ if (extras != null) {
+ extras.remove(Notification.EXTRA_LARGE_ICON);
+ extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
+ extras.remove(Notification.EXTRA_PICTURE);
+ }
}
public int describeContents() {
@@ -1706,7 +1731,7 @@
* @hide
*/
public Notification buildInto(Notification n) {
- build().cloneInto(n);
+ build().cloneInto(n, true);
return n;
}
}