Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a1e51ab authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Remove duplicate bitmaps from Notification parcels"

parents 1fec32bd ad7e72ac
Loading
Loading
Loading
Loading
+28 −0
Original line number Original line Diff line number Diff line
@@ -1941,6 +1941,7 @@ public class Notification implements Parcelable
        mSortKey = parcel.readString();
        mSortKey = parcel.readString();


        extras = Bundle.setDefusable(parcel.readBundle(), true); // may be null
        extras = Bundle.setDefusable(parcel.readBundle(), true); // may be null
        fixDuplicateExtras();


        actions = parcel.createTypedArray(Action.CREATOR); // may be null
        actions = parcel.createTypedArray(Action.CREATOR); // may be null


@@ -2388,6 +2389,33 @@ public class Notification implements Parcelable
        }
        }
    };
    };


    /**
     * Parcelling creates multiple copies of objects in {@code extras}. Fix them.
     * <p>
     * For backwards compatibility {@code extras} holds some references to "real" member data such
     * as {@link getLargeIcon()} which is mirrored by {@link #EXTRA_LARGE_ICON}. This is mostly
     * fine as long as the object stays in one process.
     * <p>
     * However, once the notification goes into a parcel each reference gets marshalled separately,
     * wasting memory. Especially with large images on Auto and TV, this is worth fixing.
     */
    private void fixDuplicateExtras() {
        if (extras != null) {
            fixDuplicateExtra(mSmallIcon, EXTRA_SMALL_ICON);
            fixDuplicateExtra(mLargeIcon, EXTRA_LARGE_ICON);
        }
    }

    /**
     * If we find an extra that's exactly the same as one of the "real" fields but refers to a
     * separate object, replace it with the field's version to avoid holding duplicate copies.
     */
    private void fixDuplicateExtra(@Nullable Parcelable original, @NonNull String extraName) {
        if (original != null && extras.getParcelable(extraName) != null) {
            extras.putParcelable(extraName, original);
        }
    }

    /**
    /**
     * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
     * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
     * layout.
     * layout.
+46 −0
Original line number Original line Diff line number Diff line
@@ -19,12 +19,17 @@ package android.app;
import static com.android.internal.util.NotificationColorUtil.satisfiesTextContrast;
import static com.android.internal.util.NotificationColorUtil.satisfiesTextContrast;


import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;


import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Icon;
import android.media.session.MediaSession;
import android.media.session.MediaSession;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.test.InstrumentationRegistry;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.runner.AndroidJUnit4;
@@ -141,6 +146,36 @@ public class NotificationTest {
        assertFalse(n.hasCompletedProgress());
        assertFalse(n.hasCompletedProgress());
    }
    }


    @Test
    public void largeIconMultipleReferences_keptAfterParcelling() {
        Icon originalIcon = Icon.createWithBitmap(BitmapFactory.decodeResource(
                mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));

        Notification n = new Notification.Builder(mContext).setLargeIcon(originalIcon).build();
        assertSame(n.getLargeIcon(), originalIcon);

        Notification q = writeAndReadParcelable(n);
        assertNotSame(q.getLargeIcon(), n.getLargeIcon());

        assertTrue(q.getLargeIcon().getBitmap().sameAs(n.getLargeIcon().getBitmap()));
        assertSame(q.getLargeIcon(), q.extras.getParcelable(Notification.EXTRA_LARGE_ICON));
    }

    @Test
    public void largeIconReferenceInExtrasOnly_keptAfterParcelling() {
        Icon originalIcon = Icon.createWithBitmap(BitmapFactory.decodeResource(
                mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));

        Notification n = new Notification.Builder(mContext).build();
        n.extras.putParcelable(Notification.EXTRA_LARGE_ICON, originalIcon);
        assertSame(n.getLargeIcon(), null);

        Notification q = writeAndReadParcelable(n);
        assertSame(q.getLargeIcon(), null);
        assertTrue(((Icon) q.extras.getParcelable(Notification.EXTRA_LARGE_ICON)).getBitmap()
                .sameAs(originalIcon.getBitmap()));
    }

    @Test
    @Test
    public void allPendingIntents_recollectedAfterReusingBuilder() {
    public void allPendingIntents_recollectedAfterReusingBuilder() {
        PendingIntent intent1 = PendingIntent.getActivity(mContext, 0, new Intent("test1"), 0);
        PendingIntent intent1 = PendingIntent.getActivity(mContext, 0, new Intent("test1"), 0);
@@ -187,4 +222,15 @@ public class NotificationTest {
                .setContentText("Text")
                .setContentText("Text")
                .setStyle(new Notification.MediaStyle().setMediaSession(session.getSessionToken()));
                .setStyle(new Notification.MediaStyle().setMediaSession(session.getSessionToken()));
    }
    }

    /**
      * Writes an arbitrary {@link Parcelable} into a {@link Parcel} using its writeToParcel
      * method before reading it out again to check that it was sent properly.
      */
    private static <T extends Parcelable> T writeAndReadParcelable(T original) {
        Parcel p = Parcel.obtain();
        p.writeParcelable(original, /* flags */ 0);
        p.setDataPosition(0);
        return p.readParcelable(/* classLoader */ null);
    }
}
}