summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Selim Cinek <cinek@google.com> 2017-07-19 23:41:44 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2017-07-19 23:41:44 +0000
commit8ffa981686dbf0f118ba14946811d33004f00f4c (patch)
tree2d21303259ab850a8da44a8eccf2a6869c9da44f
parentb0bf1d479f3b3b052f62cb30403e5b6f5457a6e9 (diff)
parent15733d1f8592de90823012570fd8db4fd3408f14 (diff)
Merge "Reducing bitmap sizes in notifications" into oc-dr1-dev
-rw-r--r--core/java/android/app/Notification.java85
-rw-r--r--core/java/android/app/NotificationManager.java1
-rw-r--r--core/java/android/widget/RemoteViews.java16
-rw-r--r--core/res/res/layout/notification_template_right_icon.xml4
-rw-r--r--core/res/res/values/dimens.xml15
-rw-r--r--core/res/res/values/symbols.xml8
-rw-r--r--graphics/java/android/graphics/drawable/Icon.java37
7 files changed, 164 insertions, 2 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 46e597aada56..d59e99321e5b 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;
@@ -1090,6 +1091,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.
*
* This is for use when rendering the notification on an audio-focused interface;
@@ -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) {
@@ -5135,6 +5145,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<? extends Style> 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
*/
private boolean isForegroundService() {
@@ -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) {
+ }
}
/**
@@ -5533,6 +5597,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
+ */
public RemoteViews makeBigContentView() {
// Replace mN.mLargeIcon with mBigLargeIcon if mBigLargeIconSet
// This covers the following cases:
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 235b8d445b1c..3a7f61a91a6d 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 7761dcafab0a..6e6235192cc9 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -199,6 +199,22 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * 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<Bitmap> 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!
*/
static class MutablePair<F, S> {
diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml
index fbf75387b786..d379256f7753 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">
<ImageView android:id="@+id/right_icon"
- android:layout_width="40dp"
- android:layout_height="40dp"
+ android:layout_width="@dimen/notification_right_icon_size"
+ android:layout_height="@dimen/notification_right_icon_size"
android:layout_gravity="top|end"
android:layout_marginTop="36dp"
android:layout_marginEnd="@dimen/notification_content_margin_end"
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 9f9c883fe6aa..743f4ad9efeb 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -580,6 +580,21 @@
<dimen name="item_touch_helper_swipe_escape_velocity">120dp</dimen>
<dimen name="item_touch_helper_swipe_escape_max_velocity">800dp</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 -->
+ <dimen name="notification_custom_view_max_image_width">450dp</dimen>
+ <!-- The maximum height of a big picture in a notification. The images will be reduced to that height in case they are bigger. This value is determined by the maximum notification height -->
+ <dimen name="notification_big_picture_max_height">284dp</dimen>
+ <!-- The maximum width of a big picture in a notification. The images will be reduced to that width in case they are bigger. This value is determined by the standard panel size -->
+ <dimen name="notification_big_picture_max_width">416dp</dimen>
+ <!-- The maximum height of a image in a media notification. The images will be reduced to that height in case they are bigger. This value is determined by the expanded media template-->
+ <dimen name="notification_media_image_max_height">140dp</dimen>
+ <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.-->
+ <dimen name="notification_media_image_max_width">280dp</dimen>
+ <!-- The size of the right icon -->
+ <dimen name="notification_right_icon_size">40dp</dimen>
+
<!-- Max width/height of the autofill data set picker as a fraction of the screen width/height -->
<dimen name="autofill_dataset_picker_max_size">90%</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 58c653b3e5a6..9a7cab4cb6b7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2946,6 +2946,14 @@
<java-symbol type="style" name="AutofillDatasetPicker" />
<java-symbol type="dimen" name="autofill_dataset_picker_max_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_media_image_max_width"/>
+ <java-symbol type="dimen" name="notification_media_image_max_height"/>
+ <java-symbol type="dimen" name="notification_right_icon_size"/>
+ <java-symbol type="dimen" name="notification_custom_view_max_image_height"/>
+ <java-symbol type="dimen" name="notification_custom_view_max_image_width"/>
+
<!-- Accessibility fingerprint gestures -->
<java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
<java-symbol type="string" name="capability_desc_canCaptureFingerprintGestures" />
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index aa38f31d66a1..c329918afc27 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -805,6 +805,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}
* is finished and your Drawable is ready.