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;
         }
     }