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 34a9fb764cb74..309496423d156 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2944,6 +2944,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}