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 @@
-