Skip to content

Commit

Permalink
Add AVIF support to AnimatedImageDecoder on Android 12+
Browse files Browse the repository at this point in the history
Animated AVIF images have been supported on the Android platform
since Android 12 via the ImageDecoder API. Enable support for AVIF
on Android 12 (Build Code S) or higher devices.

PiperOrigin-RevId: 510167795
  • Loading branch information
vigneshvg authored and glide-copybara-robot committed Feb 16, 2023
1 parent d704c89 commit 62654be
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.bumptech.glide;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeTrue;

import android.content.ContentResolver;
import android.content.Context;
import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.bumptech.glide.test.GlideApp;
import com.bumptech.glide.test.ResourceIds;
import com.bumptech.glide.testutil.ConcurrencyHelper;
import com.bumptech.glide.testutil.TearDownGlide;
import java.io.IOException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;

/**
* Tests that Glide is able to load animated images (WebP and AVIF) stored in resources and loaded
* as {@link android.graphics.drawable.AnimatedImageDrawable}s when the underlying Android platform
* supports it.
*/
@RunWith(AndroidJUnit4.class)
public class LoadAnimatedImageResourceTest {
@Rule public final TearDownGlide tearDownGlide = new TearDownGlide();
private final ConcurrencyHelper concurrency = new ConcurrencyHelper();

private Context context;

private static final boolean IS_ANIMATED_WEBP_SUPPORTED =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
private static final boolean IS_ANIMATED_AVIF_SUPPORTED =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;

@Before
public void setUp() throws IOException {
MockitoAnnotations.initMocks(this);
context = ApplicationProvider.getApplicationContext();
}

@Test
public void loadAnimatedImageResourceId_fromInt_decodesAnimatedImageDrawable_Webp() {
assumeTrue(IS_ANIMATED_WEBP_SUPPORTED);
Drawable frame =
concurrency.get(Glide.with(context).load(ResourceIds.raw.animated_webp).submit());

assertThat(frame).isNotNull();
assertThat(frame).isInstanceOf(AnimatedImageDrawable.class);
}

@Test
public void loadAnimatedImageResourceId_fromInt_decodesAnimatedImageDrawable_Avif() {
assumeTrue(IS_ANIMATED_AVIF_SUPPORTED);
Drawable frame =
concurrency.get(Glide.with(context).load(ResourceIds.raw.animated_avif).submit());

assertThat(frame).isNotNull();
assertThat(frame).isInstanceOf(AnimatedImageDrawable.class);
}

@Test
public void loadAnimatedImageUri_fromId_decodesAnimatedImageDrawable_Webp() {
assumeTrue(IS_ANIMATED_WEBP_SUPPORTED);
Uri uri =
new Uri.Builder()
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
.authority(context.getPackageName())
.path(String.valueOf(ResourceIds.raw.animated_webp))
.build();

Drawable frame = concurrency.get(GlideApp.with(context).load(uri).submit());

assertThat(frame).isNotNull();
assertThat(frame).isInstanceOf(AnimatedImageDrawable.class);
}

@Test
public void loadAnimatedImageUri_fromId_decodesAnimatedImageDrawable_Avif() {
assumeTrue(IS_ANIMATED_AVIF_SUPPORTED);
Uri uri =
new Uri.Builder()
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
.authority(context.getPackageName())
.path(String.valueOf(ResourceIds.raw.animated_avif))
.build();

Drawable frame = concurrency.get(GlideApp.with(context).load(uri).submit());

assertThat(frame).isNotNull();
assertThat(frame).isInstanceOf(AnimatedImageDrawable.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public interface raw {
int opaque_interlaced_gif = getResourceId("raw", "opaque_interlaced_gif");
int webkit_logo_p3 = getResourceId("raw", "webkit_logo_p3");
int video = getResourceId("raw", "video");
int animated_webp = getResourceId("raw", "dl_world_anim_webp");
int animated_avif = getResourceId("raw", "dl_world_anim_avif");
}

public interface drawable {
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
/**
* Allows decoding animated images using {@link ImageDecoder}.
*
* <p>Supported formats: WebP on Android P+.
* <p>Supported formats: WebP on Android P+. AVIF on Android 12/S+.
*/
@RequiresApi(Build.VERSION_CODES.P)
public final class AnimatedImageDecoder {
Expand Down Expand Up @@ -61,7 +61,8 @@ boolean handles(InputStream is) throws IOException {
}

private boolean isHandled(ImageType imageType) {
return imageType == ImageType.ANIMATED_WEBP;
return imageType == ImageType.ANIMATED_WEBP
|| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && imageType == ImageType.ANIMATED_AVIF);
}

@Synthetic
Expand Down

0 comments on commit 62654be

Please sign in to comment.