Limit the maximum size of small notification icons

Right now, the size of small notification icons is unbounded and can cause big memory usage spikes (easily measured as 50MB+). This limits the maximum size of small icon when its set as a bitmap.

Bug:193720474
Bug:209044537

Test: manual via test app
Test: atest NotificationTest
Change-Id: I684fe29d5b473d86280035e00298c8e59f47dbb7
This commit is contained in:
Jernej Virag
2022-01-24 18:01:14 +00:00
parent 2b2ddee296
commit 5c8e246f55
4 changed files with 35 additions and 0 deletions

View File

@@ -6712,6 +6712,18 @@ public class Notification implements Parcelable
return;
}
boolean isLowRam = ActivityManager.isLowRamDeviceStatic();
if (mSmallIcon != null
// Only bitmap icons can be downscaled.
&& (mSmallIcon.getType() == Icon.TYPE_BITMAP
|| mSmallIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP)) {
Resources resources = context.getResources();
int maxSize = resources.getDimensionPixelSize(
isLowRam ? R.dimen.notification_small_icon_size_low_ram
: R.dimen.notification_small_icon_size);
mSmallIcon.scaleDownIfNecessary(maxSize, maxSize);
}
if (mLargeIcon != null || largeIcon != null) {
Resources resources = context.getResources();
Class<? extends Style> style = getNotificationStyle();

View File

@@ -755,6 +755,8 @@
<dimen name="item_touch_helper_swipe_escape_velocity">120dp</dimen>
<dimen name="item_touch_helper_swipe_escape_max_velocity">800dp</dimen>
<!-- The maximum size of the small notification icon. -->
<dimen name="notification_small_icon_size">48dp</dimen>
<!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. This value is determined by the maximum notification height -->
<dimen name="notification_custom_view_max_image_height">284dp</dimen>
<!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. This value is determined a maximum notification width -->
@@ -779,6 +781,8 @@
<!-- The alpha of a disabled notification button -->
<item type="dimen" format="float" name="notification_action_disabled_alpha">0.5</item>
<!-- The maximum size of the small notification icon on low memory devices. -->
<dimen name="notification_small_icon_size_low_ram">@dimen/notification_small_icon_size</dimen>
<!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. -->
<dimen name="notification_custom_view_max_image_height_low_ram">208dp</dimen>
<!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. -->

View File

@@ -3561,6 +3561,7 @@
<java-symbol type="style" name="Theme.DeviceDefault.Autofill.Save" />
<java-symbol type="style" name="Theme.DeviceDefault.Light.Autofill.Save" />
<java-symbol type="dimen" name="notification_small_icon_size"/>
<java-symbol type="dimen" name="notification_big_picture_max_height"/>
<java-symbol type="dimen" name="notification_big_picture_max_width"/>
<java-symbol type="dimen" name="notification_right_icon_size"/>
@@ -3569,6 +3570,7 @@
<java-symbol type="dimen" name="notification_custom_view_max_image_height"/>
<java-symbol type="dimen" name="notification_custom_view_max_image_width"/>
<java-symbol type="dimen" name="notification_small_icon_size_low_ram"/>
<java-symbol type="dimen" name="notification_big_picture_max_height_low_ram"/>
<java-symbol type="dimen" name="notification_big_picture_max_width_low_ram"/>
<java-symbol type="dimen" name="notification_right_icon_size_low_ram"/>

View File

@@ -39,6 +39,7 @@ import android.content.Intent;
import android.content.LocusId;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.Icon;
@@ -503,6 +504,22 @@ public class NotificationTest {
.isGreaterThan(ContrastColorUtil.calculateLuminance(background));
}
@Test
public void testBuild_ensureSmallIconIsNotTooBig_resizesIcon() {
Icon hugeIcon = Icon.createWithBitmap(
Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888));
Notification notification = new Notification.Builder(mContext, "Channel").setSmallIcon(
hugeIcon).build();
Bitmap smallNotificationIcon = notification.getSmallIcon().getBitmap();
assertThat(smallNotificationIcon.getWidth()).isEqualTo(
mContext.getResources().getDimensionPixelSize(
R.dimen.notification_small_icon_size));
assertThat(smallNotificationIcon.getHeight()).isEqualTo(
mContext.getResources().getDimensionPixelSize(
R.dimen.notification_small_icon_size));
}
@Test
public void testColors_ensureColors_dayMode_producesValidPalette() {
Notification.Colors c = new Notification.Colors();