diff --git a/core/java/com/android/internal/widget/BigPictureNotificationImageView.java b/core/java/com/android/internal/widget/BigPictureNotificationImageView.java new file mode 100644 index 0000000000000..c34a42224f5ae --- /dev/null +++ b/core/java/com/android/internal/widget/BigPictureNotificationImageView.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import android.annotation.AttrRes; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.StyleRes; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; +import android.net.Uri; +import android.util.AttributeSet; +import android.util.Log; +import android.widget.ImageView; +import android.widget.RemoteViews; + +import java.io.IOException; + +/** + * An ImageView used by BigPicture Notifications to correctly resolve the Uri in an Icon using the + * LocalImageResolver, allowing it to support animated drawables which are not supported by + * Icon.loadDrawable(). + */ +@RemoteViews.RemoteView +public class BigPictureNotificationImageView extends ImageView { + + private static final String TAG = BigPictureNotificationImageView.class.getSimpleName(); + + public BigPictureNotificationImageView(@NonNull Context context) { + super(context); + } + + public BigPictureNotificationImageView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public BigPictureNotificationImageView(@NonNull Context context, @Nullable AttributeSet attrs, + @AttrRes int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public BigPictureNotificationImageView(@NonNull Context context, @Nullable AttributeSet attrs, + @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + @android.view.RemotableViewMethod(asyncImpl = "setImageURIAsync") + public void setImageURI(@Nullable Uri uri) { + setImageDrawable(loadImage(uri)); + } + + /** @hide **/ + public Runnable setImageURIAsync(@Nullable Uri uri) { + final Drawable drawable = loadImage(uri); + return () -> setImageDrawable(drawable); + } + + @Override + @android.view.RemotableViewMethod(asyncImpl = "setImageIconAsync") + public void setImageIcon(@Nullable Icon icon) { + setImageDrawable(loadImage(icon)); + } + + /** @hide **/ + public Runnable setImageIconAsync(@Nullable Icon icon) { + final Drawable drawable = loadImage(icon); + return () -> setImageDrawable(drawable); + } + + private Drawable loadImage(Uri uri) { + if (uri == null) return null; + try { + return LocalImageResolver.resolveImage(uri, mContext); + } catch (IOException ex) { + Log.d(TAG, "Resolve failed from " + uri, ex); + return null; + } + } + + private Drawable loadImage(Icon icon) { + if (icon == null) return null; + try { + return LocalImageResolver.resolveImage(icon, mContext); + } catch (IOException ex) { + Log.d(TAG, "Resolve failed from " + icon, ex); + return null; + } + } +} diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java index 3f205c7852580..616b69961b799 100644 --- a/core/java/com/android/internal/widget/LocalImageResolver.java +++ b/core/java/com/android/internal/widget/LocalImageResolver.java @@ -16,10 +16,11 @@ package com.android.internal.widget; +import android.annotation.Nullable; import android.content.Context; import android.graphics.ImageDecoder; -import android.graphics.drawable.AnimatedImageDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.net.Uri; import android.util.Size; @@ -31,6 +32,9 @@ public class LocalImageResolver { private static final int MAX_SAFE_ICON_SIZE_PX = 480; + /** + * Resolve an image from the given Uri using {@link ImageDecoder} + */ public static Drawable resolveImage(Uri uri, Context context) throws IOException { final ImageDecoder.Source source = ImageDecoder.createSource(context.getContentResolver(), uri); @@ -39,6 +43,25 @@ public class LocalImageResolver { return drawable; } + /** + * Get the drawable from Icon using {@link ImageDecoder} if it contains a Uri, or + * using {@link Icon#loadDrawable(Context)} otherwise. This will correctly apply the Icon's, + * tint, if present, to the drawable. + */ + public static Drawable resolveImage(Icon icon, Context context) throws IOException { + Uri uri = getResolvableUri(icon); + if (uri != null) { + Drawable result = resolveImage(uri, context); + if (icon.hasTint()) { + result.mutate(); + result.setTintList(icon.getTintList()); + result.setTintBlendMode(icon.getTintBlendMode()); + } + return result; + } + return icon.loadDrawable(context); + } + public static Drawable resolveImage(Uri uri, Context context, int maxWidth, int maxHeight) throws IOException { final ImageDecoder.Source source = @@ -73,4 +96,16 @@ public class LocalImageResolver { : 1.0; decoder.setTargetSampleSize(getPowerOfTwoForSampleRatio(ratio)); } + + /** + * Gets the Uri for this icon, assuming the icon can be treated as a pure Uri. Null otherwise. + */ + @Nullable + public static Uri getResolvableUri(@Nullable Icon icon) { + if (icon == null || (icon.getType() != Icon.TYPE_URI + && icon.getType() != Icon.TYPE_URI_ADAPTIVE_BITMAP)) { + return null; + } + return icon.getUri(); + } } diff --git a/core/res/res/layout/notification_template_material_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml index 6f3c77ff72a45..3d1ccfa5a14f3 100644 --- a/core/res/res/layout/notification_template_material_big_picture.xml +++ b/core/res/res/layout/notification_template_material_big_picture.xml @@ -58,7 +58,7 @@ -