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

Commit ea993de0 authored by Jernej Virag's avatar Jernej Virag
Browse files

Do not keep WearableExtender background bitmaps

setBackground() call was deprecated in API level 29 - however we
still keep the background bitmap in memory - both in system server
and systemui - if the app decides to set it. This is a rather big
contributor to Notification memory use.

This change makes setBackground() call a no-op on devices running API 35
or newer.

Bug: 270551184
Test: newly created CTS and unit tests run on cheetah
Change-Id: I6e50ac2e6c9b009512f0baf5442792c2a3b747ec
parent 82894ba2
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -6749,7 +6749,6 @@ package android.app {
    method public android.app.Notification.WearableExtender clone();
    method public android.app.Notification.Builder extend(android.app.Notification.Builder);
    method public java.util.List<android.app.Notification.Action> getActions();
    method @Deprecated public android.graphics.Bitmap getBackground();
    method public String getBridgeTag();
    method public int getContentAction();
    method @Deprecated public int getContentIcon();
@@ -6768,7 +6767,6 @@ package android.app {
    method @Deprecated public boolean getHintShowBackgroundOnly();
    method @Deprecated public java.util.List<android.app.Notification> getPages();
    method public boolean getStartScrollBottom();
    method @Deprecated public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
    method public android.app.Notification.WearableExtender setBridgeTag(String);
    method public android.app.Notification.WearableExtender setContentAction(int);
    method @Deprecated public android.app.Notification.WearableExtender setContentIcon(int);
+5 −0
Original line number Diff line number Diff line
@@ -23,6 +23,11 @@ package android.app {
    method @Deprecated public android.app.Notification.Builder setTimeout(long);
  }

  public static final class Notification.WearableExtender implements android.app.Notification.Extender {
    method @Deprecated public android.graphics.Bitmap getBackground();
    method @Deprecated public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
  }

}

package android.app.slice {
+40 −6
Original line number Diff line number Diff line
@@ -44,6 +44,9 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.admin.DevicePolicyManager;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
@@ -295,6 +298,15 @@ public class Notification implements Parcelable
     */
    public static final String EXTRA_REMOTE_INPUT_DRAFT = "android.remoteInputDraft";
    /**
     * The call to WearableExtender#setBackground(Bitmap) will have no effect and the passed
     * Bitmap will not be retained in memory.
     */
    @ChangeId
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
    @VisibleForTesting
    static final long WEARABLE_EXTENDER_BACKGROUND_BLOCKED = 270551184L;
    /**
     * A timestamp related to this notification, in milliseconds since the epoch.
     *
@@ -11148,9 +11160,20 @@ public class Notification implements Parcelable
                wearableBundle.putParcelableArray(KEY_PAGES, mPages.toArray(
                        new Notification[mPages.size()]));
            }
            if (mBackground != null) {
                // Keeping WearableExtender backgrounds in memory despite them being deprecated has
                // added noticeable increase in system server and system ui memory usage. After
                // target VERSION_CODE#VANILLA_ICE_CREAM the background will not be populated
                // anymore.
                if (CompatChanges.isChangeEnabled(WEARABLE_EXTENDER_BACKGROUND_BLOCKED)) {
                    Log.d(TAG, "Use of background in WearableExtenders has been deprecated and "
                            + "will not be populated anymore.");
                } else {
                    wearableBundle.putParcelable(KEY_BACKGROUND, mBackground);
                }
            }
            if (mContentIcon != 0) {
                wearableBundle.putInt(KEY_CONTENT_ICON, mContentIcon);
            }
@@ -11369,12 +11392,21 @@ public class Notification implements Parcelable
         *
         * @param background the background bitmap
         * @return this object for method chaining
         * @see android.app.Notification.WearableExtender#getBackground
         * @deprecated Background images are no longer supported.
         * @removed Not functional since {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}.
         *          The wearable background is not used by wearables anymore and uses up
         *          unnecessary memory.
         */
        @Deprecated
        public WearableExtender setBackground(Bitmap background) {
            // Keeping WearableExtender backgrounds in memory despite them being deprecated has
            // added noticeable increase in system server and system ui memory usage. After
            // target VERSION_CODE#VANILLA_ICE_CREAM the background will not be populated anymore.
            if (CompatChanges.isChangeEnabled(WEARABLE_EXTENDER_BACKGROUND_BLOCKED)) {
                Log.d(TAG, "Use of background in WearableExtenders has been deprecated and "
                        + "will not be populated anymore.");
            } else {
                mBackground = background;
            }
            return this;
        }
@@ -11384,11 +11416,13 @@ public class Notification implements Parcelable
         * will work with any notification style.
         *
         * @return the background image
         * @see android.app.Notification.WearableExtender#setBackground
         * @deprecated Background images are no longer supported.
         * @removed Not functional since {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}. The
         *          wearable background is not used by wearables anymore and uses up
         *          unnecessary memory.
         */
        @Deprecated
        public Bitmap getBackground() {
            Log.w(TAG, "Use of background in WearableExtender has been removed, returning null.");
            return mBackground;
        }
+45 −1
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import android.annotation.Nullable;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.Context;
import android.content.Intent;
import android.content.LocusId;
@@ -95,16 +96,20 @@ import android.util.Pair;
import android.widget.RemoteViews;

import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.internal.R;
import com.android.internal.util.ContrastColorUtil;

import junit.framework.Assert;

import libcore.junit.util.compat.CoreCompatChangeRule;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;

import java.util.List;
@@ -116,6 +121,9 @@ public class NotificationTest {

    private Context mContext;

    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();

    @Before
    public void setUp() {
        mContext = InstrumentationRegistry.getContext();
@@ -1777,6 +1785,42 @@ public class NotificationTest {
        assertThat(recoveredExtender.getColor()).isEqualTo(1234);
    }

    @Test
    @CoreCompatChangeRule.EnableCompatChanges({Notification.WEARABLE_EXTENDER_BACKGROUND_BLOCKED})
    public void wearableBackgroundBlockEnabled_wearableBackgroundSet_valueRemainsNull() {
        Notification.WearableExtender extender = new Notification.WearableExtender();
        Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
        extender.setBackground(bitmap);
        Notification notif =
                new Notification.Builder(mContext, "test id")
                        .setSmallIcon(1)
                        .setContentTitle("test_title")
                        .extend(extender)
                        .build();

        Notification.WearableExtender result = new Notification.WearableExtender(notif);
        Assert.assertNull(result.getBackground());
    }

    @Test
    @CoreCompatChangeRule.DisableCompatChanges({Notification.WEARABLE_EXTENDER_BACKGROUND_BLOCKED})
    public void wearableBackgroundBlockDisabled_wearableBackgroundSet_valueKeepsBitmap() {
        Notification.WearableExtender extender = new Notification.WearableExtender();
        Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
        extender.setBackground(bitmap);
        Notification notif =
                new Notification.Builder(mContext, "test id")
                        .setSmallIcon(1)
                        .setContentTitle("test_title")
                        .extend(extender)
                        .build();

        Notification.WearableExtender result = new Notification.WearableExtender(notif);
        Bitmap resultBitmap = result.getBackground();
        assertNotNull(resultBitmap);
        Assert.assertEquals(bitmap, resultBitmap);
    }

    private void assertValid(Notification.Colors c) {
        // Assert that all colors are populated
        assertThat(c.getBackgroundColor()).isNotEqualTo(Notification.COLOR_INVALID);