public AnimatedDrawableBackendImpl( AnimatedDrawableUtil animatedDrawableUtil, AnimatedImageResult animatedImageResult, Rect bounds) { mAnimatedDrawableUtil = animatedDrawableUtil; mAnimatedImageResult = animatedImageResult; mAnimatedImage = animatedImageResult.getImage(); mFrameDurationsMs = mAnimatedImage.getFrameDurations(); mAnimatedDrawableUtil.fixFrameDurations(mFrameDurationsMs); mDurationMs = mAnimatedDrawableUtil.getTotalDurationFromFrameDurations(mFrameDurationsMs); mFrameTimestampsMs = mAnimatedDrawableUtil.getFrameTimeStampsFromDurations(mFrameDurationsMs); mRenderedBounds = getBoundsToUse(mAnimatedImage, bounds); mFrameInfos = new AnimatedDrawableFrameInfo[mAnimatedImage.getFrameCount()]; for (int i = 0; i < mAnimatedImage.getFrameCount(); i++) { mFrameInfos[i] = mAnimatedImage.getFrameInfo(i); } }
private AnimationBackend createAnimationBackend(AnimatedImageResult animatedImageResult) { AnimatedDrawableBackend animatedDrawableBackend = createAnimatedDrawableBackend(animatedImageResult); BitmapFrameCache bitmapFrameCache = createBitmapFrameCache(animatedImageResult); BitmapFrameRenderer bitmapFrameRenderer = new AnimatedDrawableBackendFrameRenderer(bitmapFrameCache, animatedDrawableBackend); int numberOfFramesToPrefetch = mNumberOfFramesToPrepareSupplier.get(); BitmapFramePreparationStrategy bitmapFramePreparationStrategy = null; BitmapFramePreparer bitmapFramePreparer = null; if (numberOfFramesToPrefetch > 0) { bitmapFramePreparationStrategy = new FixedNumberBitmapFramePreparationStrategy(); bitmapFramePreparer = createBitmapFramePreparer(bitmapFrameRenderer); } BitmapAnimationBackend bitmapAnimationBackend = new BitmapAnimationBackend( mPlatformBitmapFactory, bitmapFrameCache, new AnimatedDrawableBackendAnimationInformation(animatedDrawableBackend), bitmapFrameRenderer, bitmapFramePreparationStrategy, bitmapFramePreparer); return AnimationBackendDelegateWithInactivityCheck.createForBackend( bitmapAnimationBackend, mMonotonicClock, mScheduledExecutorServiceForUiThread); }
private BitmapFrameCache createBitmapFrameCache(AnimatedImageResult animatedImageResult) { switch (mCachingStrategySupplier.get()) { case CACHING_STRATEGY_FRESCO_CACHE: return new FrescoFrameCache(createAnimatedFrameCache(animatedImageResult), true); case CACHING_STRATEGY_FRESCO_CACHE_NO_REUSING: return new FrescoFrameCache(createAnimatedFrameCache(animatedImageResult), false); case CACHING_STRATEGY_KEEP_LAST_CACHE: return new KeepLastFrameCache(); case CACHING_STRATEGY_NO_CACHE: default: return new NoOpCache(); } }
private AnimatedDrawableBackendProvider getAnimatedDrawableBackendProvider() { if (mAnimatedDrawableBackendProvider == null) { mAnimatedDrawableBackendProvider = new AnimatedDrawableBackendProvider() { @Override public AnimatedDrawableBackend get(AnimatedImageResult animatedImageResult, Rect bounds) { return new AnimatedDrawableBackendImpl( getAnimatedDrawableUtil(), animatedImageResult, bounds); } }; } return mAnimatedDrawableBackendProvider; }
private AnimatedImageFactory buildAnimatedImageFactory() { AnimatedDrawableBackendProvider animatedDrawableBackendProvider = new AnimatedDrawableBackendProvider() { @Override public AnimatedDrawableBackend get(AnimatedImageResult imageResult, Rect bounds) { return new AnimatedDrawableBackendImpl(getAnimatedDrawableUtil(), imageResult, bounds); } }; return new AnimatedImageFactoryImpl(animatedDrawableBackendProvider, mPlatformBitmapFactory); }
@Override public void close() { AnimatedImageResult imageResult; synchronized (this) { if (mImageResult == null) { return; } imageResult = mImageResult; mImageResult = null; } imageResult.dispose(); }
private CloseableImage getCloseableImage( ImageDecodeOptions options, AnimatedImage image, Bitmap.Config bitmapConfig) { List<CloseableReference<Bitmap>> decodedFrames = null; CloseableReference<Bitmap> previewBitmap = null; try { final int frameForPreview = options.useLastFrameForPreview ? image.getFrameCount() - 1 : 0; if (options.forceStaticImage) { return new CloseableStaticBitmap( createPreviewBitmap(image, bitmapConfig, frameForPreview), ImmutableQualityInfo.FULL_QUALITY, 0); } if (options.decodeAllFrames) { decodedFrames = decodeAllFrames(image, bitmapConfig); previewBitmap = CloseableReference.cloneOrNull(decodedFrames.get(frameForPreview)); } if (options.decodePreviewFrame && previewBitmap == null) { previewBitmap = createPreviewBitmap(image, bitmapConfig, frameForPreview); } AnimatedImageResult animatedImageResult = AnimatedImageResult.newBuilder(image) .setPreviewBitmap(previewBitmap) .setFrameForPreview(frameForPreview) .setDecodedFrames(decodedFrames) .build(); return new CloseableAnimatedImage(animatedImageResult); } finally { CloseableReference.closeSafely(previewBitmap); CloseableReference.closeSafely(decodedFrames); } }
@Test public void testCreateDefaults() { WebPImage mockWebPImage = mock(WebPImage.class); // Expect a call to WebPImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mWebPImageMock.decode(byteBuffer.getNativePtr(), byteBuffer.size())) .thenReturn(mockWebPImage); EncodedImage encodedImage = new EncodedImage( CloseableReference.of(byteBuffer, FAKE_RESOURCE_RELEASER)); encodedImage.setImageFormat(ImageFormat.UNKNOWN); CloseableAnimatedImage closeableImage = (CloseableAnimatedImage) mAnimatedImageFactory.decodeWebP( encodedImage, ImageDecodeOptions.defaults(), DEFAULT_BITMAP_CONFIG); // Verify we got the right result AnimatedImageResult imageResult = closeableImage.getImageResult(); assertSame(mockWebPImage, imageResult.getImage()); assertNull(imageResult.getPreviewBitmap()); assertFalse(imageResult.hasDecodedFrame(0)); // Should not have interacted with these. verifyZeroInteractions(mMockAnimatedDrawableBackendProvider); verifyZeroInteractions(mMockBitmapFactory); }
@Test public void testCreateDefaults() { GifImage mockGifImage = mock(GifImage.class); // Expect a call to GifImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mGifImageMock.decode(byteBuffer.getNativePtr(), byteBuffer.size())) .thenReturn(mockGifImage); EncodedImage encodedImage = new EncodedImage( CloseableReference.of(byteBuffer, FAKE_RESOURCE_RELEASER)); encodedImage.setImageFormat(ImageFormat.UNKNOWN); CloseableAnimatedImage closeableImage = (CloseableAnimatedImage) mAnimatedImageFactory.decodeGif( encodedImage, ImageDecodeOptions.defaults(), DEFAULT_BITMAP_CONFIG); // Verify we got the right result AnimatedImageResult imageResult = closeableImage.getImageResult(); assertSame(mockGifImage, imageResult.getImage()); assertNull(imageResult.getPreviewBitmap()); assertFalse(imageResult.hasDecodedFrame(0)); // Should not have interacted with these. verifyZeroInteractions(mMockAnimatedDrawableBackendProvider); verifyZeroInteractions(mMockBitmapFactory); }
private AnimationBackend createAnimationBackend(AnimatedImageResult animatedImageResult) { AnimatedDrawableBackend animatedDrawableBackend = createAnimatedDrawableBackend(animatedImageResult); BitmapFrameCache bitmapFrameCache = createBitmapFrameCache(animatedImageResult); BitmapFrameRenderer bitmapFrameRenderer = new AnimatedDrawableBackendFrameRenderer(bitmapFrameCache, animatedDrawableBackend); int numberOfFramesToPrefetch = mNumberOfFramesToPrepareSupplier.get(); BitmapFramePreparationStrategy bitmapFramePreparationStrategy = null; BitmapFramePreparer bitmapFramePreparer = null; if (numberOfFramesToPrefetch > 0) { bitmapFramePreparationStrategy = new FixedNumberBitmapFramePreparationStrategy(numberOfFramesToPrefetch); bitmapFramePreparer = createBitmapFramePreparer(bitmapFrameRenderer); } BitmapAnimationBackend bitmapAnimationBackend = new BitmapAnimationBackend( mPlatformBitmapFactory, bitmapFrameCache, new AnimatedDrawableBackendAnimationInformation(animatedDrawableBackend), bitmapFrameRenderer, bitmapFramePreparationStrategy, bitmapFramePreparer); return AnimationBackendDelegateWithInactivityCheck.createForBackend( bitmapAnimationBackend, mMonotonicClock, mScheduledExecutorServiceForUiThread); }
private AnimatedDrawableBackend createAnimatedDrawableBackend( AnimatedImageResult animatedImageResult) { AnimatedImage animatedImage = animatedImageResult.getImage(); Rect initialBounds = new Rect(0, 0, animatedImage.getWidth(), animatedImage.getHeight()); return mAnimatedDrawableBackendProvider.get(animatedImageResult, initialBounds); }
private AnimatedFrameCache createAnimatedFrameCache( final AnimatedImageResult animatedImageResult) { return new AnimatedFrameCache( new AnimationFrameCacheKey(animatedImageResult.hashCode()), mBackingCache); }
public CloseableAnimatedImage(AnimatedImageResult imageResult) { mImageResult = imageResult; }
public synchronized AnimatedImageResult getImageResult() { return mImageResult; }
@Override public AnimatedImageResult getAnimatedImageResult() { return mAnimatedImageResult; }
@Override public AnimatedImageResult getAnimatedImageResult() { return null; }
@Test public void testCreateWithPreviewBitmap() throws Exception { WebPImage mockWebPImage = mock(WebPImage.class); Bitmap mockBitmap = MockBitmapFactory.create(50, 50, DEFAULT_BITMAP_CONFIG); // Expect a call to WebPImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mWebPImageMock.decode(byteBuffer.getNativePtr(), byteBuffer.size())) .thenReturn(mockWebPImage); when(mockWebPImage.getWidth()).thenReturn(50); when(mockWebPImage.getHeight()).thenReturn(50); // For decoding preview frame, expect some calls. final AnimatedDrawableBackend mockAnimatedDrawableBackend = createAnimatedDrawableBackendMock(1); when(mMockAnimatedDrawableBackendProvider.get( any(AnimatedImageResult.class), isNull(Rect.class))) .thenReturn(mockAnimatedDrawableBackend); when(mMockBitmapFactory.createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG)) .thenReturn(CloseableReference.of(mockBitmap, FAKE_BITMAP_RESOURCE_RELEASER)); AnimatedImageCompositor mockCompositor = mock(AnimatedImageCompositor.class); PowerMockito.whenNew(AnimatedImageCompositor.class) .withAnyArguments() .thenReturn(mockCompositor); ImageDecodeOptions imageDecodeOptions = ImageDecodeOptions.newBuilder() .setDecodePreviewFrame(true) .build(); EncodedImage encodedImage = new EncodedImage( CloseableReference.of(byteBuffer, FAKE_RESOURCE_RELEASER)); encodedImage.setImageFormat(ImageFormat.UNKNOWN); CloseableAnimatedImage closeableImage = (CloseableAnimatedImage) mAnimatedImageFactory.decodeWebP( encodedImage, imageDecodeOptions, DEFAULT_BITMAP_CONFIG); // Verify we got the right result AnimatedImageResult imageResult = closeableImage.getImageResult(); assertSame(mockWebPImage, imageResult.getImage()); assertNotNull(imageResult.getPreviewBitmap()); assertFalse(imageResult.hasDecodedFrame(0)); // Should not have interacted with these. verify(mMockAnimatedDrawableBackendProvider).get( any(AnimatedImageResult.class), isNull(Rect.class)); verifyNoMoreInteractions(mMockAnimatedDrawableBackendProvider); verify(mMockBitmapFactory).createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG); verifyNoMoreInteractions(mMockBitmapFactory); verify(mockCompositor).renderFrame(0, mockBitmap); }
@Test public void testCreateWithDecodeAlFrames() throws Exception { WebPImage mockWebPImage = mock(WebPImage.class); Bitmap mockBitmap1 = MockBitmapFactory.create(50, 50, DEFAULT_BITMAP_CONFIG); Bitmap mockBitmap2 = MockBitmapFactory.create(50, 50, DEFAULT_BITMAP_CONFIG); // Expect a call to WebPImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mWebPImageMock.decode(byteBuffer.getNativePtr(), byteBuffer.size())) .thenReturn(mockWebPImage); when(mockWebPImage.getWidth()).thenReturn(50); when(mockWebPImage.getHeight()).thenReturn(50); // For decoding preview frame, expect some calls. final AnimatedDrawableBackend mockAnimatedDrawableBackend = createAnimatedDrawableBackendMock(2); when( mMockAnimatedDrawableBackendProvider.get( any(AnimatedImageResult.class), isNull(Rect.class))) .thenReturn(mockAnimatedDrawableBackend); when(mMockBitmapFactory.createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG)) .thenReturn(CloseableReference.of(mockBitmap1, FAKE_BITMAP_RESOURCE_RELEASER)) .thenReturn(CloseableReference.of(mockBitmap2, FAKE_BITMAP_RESOURCE_RELEASER)); AnimatedImageCompositor mockCompositor = mock(AnimatedImageCompositor.class); PowerMockito.whenNew(AnimatedImageCompositor.class) .withAnyArguments() .thenReturn(mockCompositor); ImageDecodeOptions imageDecodeOptions = ImageDecodeOptions.newBuilder() .setDecodePreviewFrame(true) .setDecodeAllFrames(true) .build(); EncodedImage encodedImage = new EncodedImage( CloseableReference.of(byteBuffer, FAKE_RESOURCE_RELEASER)); encodedImage.setImageFormat(ImageFormat.UNKNOWN); CloseableAnimatedImage closeableImage = (CloseableAnimatedImage) mAnimatedImageFactory.decodeWebP( encodedImage, imageDecodeOptions, DEFAULT_BITMAP_CONFIG); // Verify we got the right result AnimatedImageResult imageResult = closeableImage.getImageResult(); assertSame(mockWebPImage, imageResult.getImage()); assertNotNull(imageResult.getDecodedFrame(0)); assertNotNull(imageResult.getDecodedFrame(1)); assertNotNull(imageResult.getPreviewBitmap()); // Should not have interacted with these. verify(mMockAnimatedDrawableBackendProvider).get( any(AnimatedImageResult.class), isNull(Rect.class)); verifyNoMoreInteractions(mMockAnimatedDrawableBackendProvider); verify(mMockBitmapFactory, times(2)).createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG); verifyNoMoreInteractions(mMockBitmapFactory); verify(mockCompositor).renderFrame(0, mockBitmap1); verify(mockCompositor).renderFrame(1, mockBitmap2); }
@Test public void testCreateWithPreviewBitmap() throws Exception { GifImage mockGifImage = mock(GifImage.class); Bitmap mockBitmap = MockBitmapFactory.create(50, 50, DEFAULT_BITMAP_CONFIG); // Expect a call to WebPImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mGifImageMock.decode(byteBuffer.getNativePtr(), byteBuffer.size())) .thenReturn(mockGifImage); when(mockGifImage.getWidth()).thenReturn(50); when(mockGifImage.getHeight()).thenReturn(50); // For decoding preview frame, expect some calls. final AnimatedDrawableBackend mockAnimatedDrawableBackend = createAnimatedDrawableBackendMock(1); when(mMockAnimatedDrawableBackendProvider.get( any(AnimatedImageResult.class), isNull(Rect.class))) .thenReturn(mockAnimatedDrawableBackend); when(mMockBitmapFactory.createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG)) .thenReturn(CloseableReference.of(mockBitmap, FAKE_BITMAP_RESOURCE_RELEASER)); AnimatedImageCompositor mockCompositor = mock(AnimatedImageCompositor.class); PowerMockito.whenNew(AnimatedImageCompositor.class) .withAnyArguments() .thenReturn(mockCompositor); ImageDecodeOptions imageDecodeOptions = ImageDecodeOptions.newBuilder() .setDecodePreviewFrame(true) .build(); EncodedImage encodedImage = new EncodedImage( CloseableReference.of(byteBuffer, FAKE_RESOURCE_RELEASER)); encodedImage.setImageFormat(ImageFormat.UNKNOWN); CloseableAnimatedImage closeableImage = (CloseableAnimatedImage) mAnimatedImageFactory.decodeGif( encodedImage, imageDecodeOptions, DEFAULT_BITMAP_CONFIG); // Verify we got the right result AnimatedImageResult imageResult = closeableImage.getImageResult(); assertSame(mockGifImage, imageResult.getImage()); assertNotNull(imageResult.getPreviewBitmap()); assertFalse(imageResult.hasDecodedFrame(0)); // Should not have interacted with these. verify(mMockAnimatedDrawableBackendProvider).get( any(AnimatedImageResult.class), isNull(Rect.class)); verifyNoMoreInteractions(mMockAnimatedDrawableBackendProvider); verify(mMockBitmapFactory).createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG); verifyNoMoreInteractions(mMockBitmapFactory); verify(mockCompositor).renderFrame(0, mockBitmap); }
@Test public void testCreateWithDecodeAlFrames() throws Exception { GifImage mockGifImage = mock(GifImage.class); Bitmap mockBitmap1 = MockBitmapFactory.create(50, 50, DEFAULT_BITMAP_CONFIG); Bitmap mockBitmap2 = MockBitmapFactory.create(50, 50, DEFAULT_BITMAP_CONFIG); // Expect a call to GifImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mGifImageMock.decode(byteBuffer.getNativePtr(), byteBuffer.size())) .thenReturn(mockGifImage); when(mockGifImage.getWidth()).thenReturn(50); when(mockGifImage.getHeight()).thenReturn(50); // For decoding preview frame, expect some calls. final AnimatedDrawableBackend mockAnimatedDrawableBackend = createAnimatedDrawableBackendMock(2); when( mMockAnimatedDrawableBackendProvider.get( any(AnimatedImageResult.class), isNull(Rect.class))) .thenReturn(mockAnimatedDrawableBackend); when(mMockBitmapFactory.createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG)) .thenReturn(CloseableReference.of(mockBitmap1, FAKE_BITMAP_RESOURCE_RELEASER)) .thenReturn(CloseableReference.of(mockBitmap2, FAKE_BITMAP_RESOURCE_RELEASER)); AnimatedImageCompositor mockCompositor = mock(AnimatedImageCompositor.class); PowerMockito.whenNew(AnimatedImageCompositor.class) .withAnyArguments() .thenReturn(mockCompositor); ImageDecodeOptions imageDecodeOptions = ImageDecodeOptions.newBuilder() .setDecodePreviewFrame(true) .setDecodeAllFrames(true) .build(); EncodedImage encodedImage = new EncodedImage( CloseableReference.of(byteBuffer, FAKE_RESOURCE_RELEASER)); encodedImage.setImageFormat(ImageFormat.UNKNOWN); CloseableAnimatedImage closeableImage = (CloseableAnimatedImage) mAnimatedImageFactory.decodeGif( encodedImage, imageDecodeOptions, DEFAULT_BITMAP_CONFIG); // Verify we got the right result AnimatedImageResult imageResult = closeableImage.getImageResult(); assertSame(mockGifImage, imageResult.getImage()); assertNotNull(imageResult.getDecodedFrame(0)); assertNotNull(imageResult.getDecodedFrame(1)); assertNotNull(imageResult.getPreviewBitmap()); // Should not have interacted with these. verify(mMockAnimatedDrawableBackendProvider).get( any(AnimatedImageResult.class), isNull(Rect.class)); verifyNoMoreInteractions(mMockAnimatedDrawableBackendProvider); verify(mMockBitmapFactory, times(2)).createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG); verifyNoMoreInteractions(mMockBitmapFactory); verify(mockCompositor).renderFrame(0, mockBitmap1); verify(mockCompositor).renderFrame(1, mockBitmap2); }
/** * Creates a new {@link AnimatedDrawableBackend}. * * @param animatedImageResult the image result. * @param bounds the initial bounds for the drawable * @return a new {@link AnimatedDrawableBackend} */ AnimatedDrawableBackend get(AnimatedImageResult animatedImageResult, Rect bounds);