Downscale oversized MessagingStyle avatars
Notification API downscales oversized icons in all formats except in MessagingStyle. This seems to be an oversight that can cause massive memory usage.
This downscales avatars to a reasonable size if they're too big.
Bug:193720474
Bug:221890932
Test: atest NotificationTest
Built a test app with 4000x4000 avatar icon.
Memory usage went from 250MB to ~170KB per notification.
Change-Id: I35377cdb5d61ee6e23fccc2bffb5d3aec6ca2b7d
This commit is contained in:
@@ -7917,6 +7917,8 @@ public class Notification implements Parcelable
|
||||
* @hide
|
||||
*/
|
||||
public MessagingStyle setShortcutIcon(@Nullable Icon conversationIcon) {
|
||||
// TODO(b/228941516): This icon should be downscaled to avoid using too much memory,
|
||||
// see reduceImageSizes.
|
||||
mShortcutIcon = conversationIcon;
|
||||
return this;
|
||||
}
|
||||
@@ -8423,6 +8425,51 @@ public class Notification implements Parcelable
|
||||
return makeMessagingView(StandardTemplateParams.VIEW_TYPE_HEADS_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void reduceImageSizes(Context context) {
|
||||
super.reduceImageSizes(context);
|
||||
Resources resources = context.getResources();
|
||||
boolean isLowRam = ActivityManager.isLowRamDeviceStatic();
|
||||
if (mShortcutIcon != null) {
|
||||
int maxSize = resources.getDimensionPixelSize(
|
||||
isLowRam ? R.dimen.notification_small_icon_size_low_ram
|
||||
: R.dimen.notification_small_icon_size);
|
||||
mShortcutIcon.scaleDownIfNecessary(maxSize, maxSize);
|
||||
}
|
||||
|
||||
int maxAvatarSize = resources.getDimensionPixelSize(
|
||||
isLowRam ? R.dimen.notification_person_icon_max_size
|
||||
: R.dimen.notification_person_icon_max_size_low_ram);
|
||||
if (mUser != null && mUser.getIcon() != null) {
|
||||
mUser.getIcon().scaleDownIfNecessary(maxAvatarSize, maxAvatarSize);
|
||||
}
|
||||
|
||||
reduceMessagesIconSizes(mMessages, maxAvatarSize);
|
||||
reduceMessagesIconSizes(mHistoricMessages, maxAvatarSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
private static void reduceMessagesIconSizes(@Nullable List<Message> messages, int maxSize) {
|
||||
if (messages == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Message message : messages) {
|
||||
Person sender = message.mSender;
|
||||
if (sender != null) {
|
||||
Icon icon = sender.getIcon();
|
||||
if (icon != null) {
|
||||
icon.scaleDownIfNecessary(maxSize, maxSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Message {
|
||||
/** @hide */
|
||||
public static final String KEY_TEXT = "text";
|
||||
|
||||
@@ -779,6 +779,10 @@
|
||||
<dimen name="notification_left_icon_start">@dimen/notification_icon_circle_start</dimen>
|
||||
<!-- The alpha of a disabled notification button -->
|
||||
<item type="dimen" format="float" name="notification_action_disabled_alpha">0.5</item>
|
||||
<!-- The maximum size of Person avatar image in MessagingStyle notifications.
|
||||
This is bigger than displayed because listeners can use it for other displays
|
||||
e.g. wearables. -->
|
||||
<dimen name="notification_person_icon_max_size">144dp</dimen>
|
||||
|
||||
<!-- 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>
|
||||
@@ -792,6 +796,10 @@
|
||||
<dimen name="notification_big_picture_max_width_low_ram">294dp</dimen>
|
||||
<!-- The size of the right icon image when on low ram -->
|
||||
<dimen name="notification_right_icon_size_low_ram">@dimen/notification_right_icon_size</dimen>
|
||||
<!-- The maximum size of Person avatar image in MessagingStyle notifications.
|
||||
This is bigger than displayed because listeners can use it for other displays
|
||||
e.g. wearables. -->
|
||||
<dimen name="notification_person_icon_max_size_low_ram">96dp</dimen>
|
||||
<!-- The maximum size of the grayscale icon -->
|
||||
<dimen name="notification_grayscale_icon_max_size">256dp</dimen>
|
||||
|
||||
|
||||
@@ -3603,6 +3603,7 @@
|
||||
<java-symbol type="dimen" name="notification_actions_icon_drawable_size"/>
|
||||
<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_person_icon_max_size" />
|
||||
|
||||
<java-symbol type="dimen" name="notification_small_icon_size_low_ram"/>
|
||||
<java-symbol type="dimen" name="notification_big_picture_max_height_low_ram"/>
|
||||
@@ -3611,6 +3612,7 @@
|
||||
<java-symbol type="dimen" name="notification_grayscale_icon_max_size"/>
|
||||
<java-symbol type="dimen" name="notification_custom_view_max_image_height_low_ram"/>
|
||||
<java-symbol type="dimen" name="notification_custom_view_max_image_width_low_ram"/>
|
||||
<java-symbol type="dimen" name="notification_person_icon_max_size_low_ram" />
|
||||
|
||||
<!-- Accessibility fingerprint gestures -->
|
||||
<java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
|
||||
|
||||
@@ -520,6 +520,70 @@ public class NotificationTest {
|
||||
R.dimen.notification_small_icon_size));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuild_ensureMessagingUserIsNotTooBig_resizesIcon() {
|
||||
Icon hugeIcon = Icon.createWithBitmap(
|
||||
Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888));
|
||||
Icon hugeMessageAvatar = Icon.createWithBitmap(
|
||||
Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888));
|
||||
Icon hugeHistoricMessageAvatar = Icon.createWithBitmap(
|
||||
Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888));
|
||||
|
||||
Notification.MessagingStyle style = new Notification.MessagingStyle(
|
||||
new Person.Builder().setIcon(hugeIcon).setName("A User").build());
|
||||
style.addMessage(new Notification.MessagingStyle.Message("A message", 123456,
|
||||
new Person.Builder().setIcon(hugeMessageAvatar).setName("A Sender").build()));
|
||||
style.addHistoricMessage(new Notification.MessagingStyle.Message("A message", 123456,
|
||||
new Person.Builder().setIcon(hugeHistoricMessageAvatar).setName(
|
||||
"A Historic Sender").build()));
|
||||
Notification notification = new Notification.Builder(mContext, "Channel").setStyle(
|
||||
style).build();
|
||||
|
||||
Bitmap personIcon = style.getUser().getIcon().getBitmap();
|
||||
assertThat(personIcon.getWidth()).isEqualTo(
|
||||
mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_person_icon_max_size));
|
||||
assertThat(personIcon.getHeight()).isEqualTo(
|
||||
mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_person_icon_max_size));
|
||||
|
||||
Bitmap avatarIcon = style.getMessages().get(0).getSenderPerson().getIcon().getBitmap();
|
||||
assertThat(avatarIcon.getWidth()).isEqualTo(
|
||||
mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_person_icon_max_size));
|
||||
assertThat(avatarIcon.getHeight()).isEqualTo(
|
||||
mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_person_icon_max_size));
|
||||
|
||||
Bitmap historicAvatarIcon = style.getHistoricMessages().get(
|
||||
0).getSenderPerson().getIcon().getBitmap();
|
||||
assertThat(historicAvatarIcon.getWidth()).isEqualTo(
|
||||
mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_person_icon_max_size));
|
||||
assertThat(historicAvatarIcon.getHeight()).isEqualTo(
|
||||
mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_person_icon_max_size));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuild_ensureMessagingShortcutIconIsNotTooBig_resizesIcon() {
|
||||
Icon hugeIcon = Icon.createWithBitmap(
|
||||
Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888));
|
||||
Notification.MessagingStyle style = new Notification.MessagingStyle(
|
||||
new Person.Builder().setName("A User").build()).setShortcutIcon(hugeIcon);
|
||||
|
||||
Notification notification = new Notification.Builder(mContext, "Channel").setStyle(
|
||||
style).build();
|
||||
Bitmap shortcutIcon = style.getShortcutIcon().getBitmap();
|
||||
|
||||
assertThat(shortcutIcon.getWidth()).isEqualTo(
|
||||
mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_small_icon_size));
|
||||
assertThat(shortcutIcon.getHeight()).isEqualTo(
|
||||
mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_small_icon_size));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColors_ensureColors_dayMode_producesValidPalette() {
|
||||
Notification.Colors c = new Notification.Colors();
|
||||
|
||||
Reference in New Issue
Block a user