From 15733d1f8592de90823012570fd8db4fd3408f14 Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Tue, 11 Jul 2017 13:19:59 +0200 Subject: [PATCH] Reducing bitmap sizes in notifications Bitmap sizes could be arbitrary large when they were sent over to the system. We're now reducing them to reasonable sizes.s Also fixed that notification bitmaps were not put into ashmem anymore since it got lost in a refactor. Test: code inspection Bug: 62319200 Merged-In: I87db7656e749666b9eab1f67fd497f155c407e18 Change-Id: I87db7656e749666b9eab1f67fd497f155c407e18 --- core/java/android/app/Notification.java | 85 +++++++++++++++++++ .../java/android/app/NotificationManager.java | 1 + core/java/android/widget/RemoteViews.java | 16 ++++ .../notification_template_right_icon.xml | 4 +- core/res/res/values/dimens.xml | 15 ++++ core/res/res/values/symbols.xml | 8 ++ .../java/android/graphics/drawable/Icon.java | 37 ++++++++ 7 files changed, 164 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 46e597aada56a..d59e99321e5b1 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -33,6 +33,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ShortcutInfo; import android.content.res.ColorStateList; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -1089,6 +1090,11 @@ public class Notification implements Parcelable */ public static final String EXTRA_CONTAINS_CUSTOM_VIEW = "android.contains.customView"; + /** + * @hide + */ + public static final String EXTRA_REDUCED_IMAGES = "android.reduced.images"; + /** * {@link #extras} key: the audio contents of this notification. * @@ -4943,9 +4949,13 @@ public class Notification implements Parcelable buildUnstyled(); if (mStyle != null) { + mStyle.reduceImageSizes(mContext); + mStyle.purgeResources(); mStyle.buildStyled(mN); } + mN.reduceImageSizes(mContext); + if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N && (useExistingRemoteView())) { if (mN.contentView == null) { @@ -5134,6 +5144,52 @@ public class Notification implements Parcelable } } + /** + * Reduces the image sizes to conform to a maximum allowed size. This also processes all custom + * remote views. + * + * @hide + */ + void reduceImageSizes(Context context) { + if (extras.getBoolean(EXTRA_REDUCED_IMAGES)) { + return; + } + if (mLargeIcon != null || largeIcon != null) { + Resources resources = context.getResources(); + Class style = getNotificationStyle(); + int maxWidth = resources.getDimensionPixelSize(R.dimen.notification_right_icon_size); + int maxHeight = maxWidth; + if (MediaStyle.class.equals(style) + || DecoratedMediaCustomViewStyle.class.equals(style)) { + maxHeight = resources.getDimensionPixelSize( + R.dimen.notification_media_image_max_height); + maxWidth = resources.getDimensionPixelSize( + R.dimen.notification_media_image_max_width); + } + if (mLargeIcon != null) { + mLargeIcon.scaleDownIfNecessary(maxWidth, maxHeight); + } + if (largeIcon != null) { + largeIcon = Icon.scaleDownIfNecessary(largeIcon, maxWidth, maxHeight); + } + } + reduceImageSizesForRemoteView(contentView, context); + reduceImageSizesForRemoteView(headsUpContentView, context); + reduceImageSizesForRemoteView(bigContentView, context); + extras.putBoolean(EXTRA_REDUCED_IMAGES, true); + } + + private void reduceImageSizesForRemoteView(RemoteViews remoteView, Context context) { + if (remoteView != null) { + Resources resources = context.getResources(); + int maxWidth = resources.getDimensionPixelSize( + R.dimen.notification_custom_view_max_image_width); + int maxHeight = resources.getDimensionPixelSize( + R.dimen.notification_custom_view_max_image_height); + remoteView.reduceImageSizes(maxWidth, maxHeight); + } + } + /** * @return whether this notification is a foreground service notification */ @@ -5435,6 +5491,14 @@ public class Notification implements Parcelable public boolean displayCustomViewInline() { return false; } + + /** + * Reduces the image sizes contained in this style. + * + * @hide + */ + public void reduceImageSizes(Context context) { + } } /** @@ -5530,6 +5594,27 @@ public class Notification implements Parcelable } } + /** + * @hide + */ + @Override + public void reduceImageSizes(Context context) { + super.reduceImageSizes(context); + Resources resources = context.getResources(); + if (mPicture != null) { + int maxPictureWidth = resources.getDimensionPixelSize( + R.dimen.notification_big_picture_max_height); + int maxPictureHeight = resources.getDimensionPixelSize( + R.dimen.notification_big_picture_max_width); + mPicture = Icon.scaleDownIfNecessary(mPicture, maxPictureWidth, maxPictureHeight); + } + if (mBigLargeIcon != null) { + int rightIconSize = resources.getDimensionPixelSize( + R.dimen.notification_right_icon_size); + mBigLargeIcon.scaleDownIfNecessary(rightIconSize, rightIconSize); + } + } + /** * @hide */ diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 235b8d445b1c8..3a7f61a91a6d0 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -312,6 +312,7 @@ public class NotificationManager { } } if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")"); + notification.reduceImageSizes(mContext); final Notification copy = Builder.maybeCloneStrippedForDelivery(notification); try { service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 7761dcafab0a8..6e6235192cc94 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -198,6 +198,22 @@ public class RemoteViews implements Parcelable, Filter { mActions.add(new SetRemoteInputsAction(viewId, remoteInputs)); } + /** + * Reduces all images and ensures that they are all below the given sizes. + * + * @param maxWidth the maximum width allowed + * @param maxHeight the maximum height allowed + * + * @hide + */ + public void reduceImageSizes(int maxWidth, int maxHeight) { + ArrayList cache = mBitmapCache.mBitmaps; + for (int i = 0; i < cache.size(); i++) { + Bitmap bitmap = cache.get(i); + cache.set(i, Icon.scaleDownIfNecessary(bitmap, maxWidth, maxHeight)); + } + } + /** * Handle with care! */ diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml index fbf75387b786d..d379256f7753f 100644 --- a/core/res/res/layout/notification_template_right_icon.xml +++ b/core/res/res/layout/notification_template_right_icon.xml @@ -21,8 +21,8 @@ android:layout_height="wrap_content" android:layout_gravity="top|end"> 120dp 800dp + + 284dp + + 450dp + + 284dp + + 416dp + + 140dp + + 280dp + + 40dp + 90% diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ad9b5af37788b..e27e8daf06074 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2942,6 +2942,14 @@ + + + + + + + + diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java index aa38f31d66a16..c329918afc27b 100644 --- a/graphics/java/android/graphics/drawable/Icon.java +++ b/graphics/java/android/graphics/drawable/Icon.java @@ -804,6 +804,43 @@ public final class Icon implements Parcelable { } }; + /** + * Scale down a bitmap to a given max width and max height. The scaling will be done in a uniform way + * @param bitmap the bitmap to scale down + * @param maxWidth the maximum width allowed + * @param maxHeight the maximum height allowed + * + * @return the scaled bitmap if necessary or the original bitmap if no scaling was needed + * @hide + */ + public static Bitmap scaleDownIfNecessary(Bitmap bitmap, int maxWidth, int maxHeight) { + int bitmapWidth = bitmap.getWidth(); + int bitmapHeight = bitmap.getHeight(); + if (bitmapWidth > maxWidth || bitmapHeight > maxHeight) { + float scale = Math.min((float) maxWidth / bitmapWidth, + (float) maxHeight / bitmapHeight); + bitmap = Bitmap.createScaledBitmap(bitmap, (int) (scale * bitmapWidth), + (int) (scale * bitmapHeight), true /* filter */); + } + return bitmap; + } + + /** + * Scale down this icon to a given max width and max height. + * The scaling will be done in a uniform way and currently only bitmaps are supported. + * @param maxWidth the maximum width allowed + * @param maxHeight the maximum height allowed + * + * @hide + */ + public void scaleDownIfNecessary(int maxWidth, int maxHeight) { + if (mType != TYPE_BITMAP && mType != TYPE_ADAPTIVE_BITMAP) { + return; + } + Bitmap bitmap = getBitmap(); + setBitmap(scaleDownIfNecessary(bitmap, maxWidth, maxHeight)); + } + /** * Implement this interface to receive a callback when * {@link #loadDrawableAsync(Context, OnDrawableLoadedListener, Handler) loadDrawableAsync}