From a4e10146f353bcf7c3480c5285d5dc16c9a0e36c Mon Sep 17 00:00:00 2001 From: zjupure Date: Sat, 25 Aug 2018 10:48:04 +0800 Subject: [PATCH 1/2] Add an option that supports reusing tdisk cache for thumbnails from local videos --- .../core/ImagePipelineExperiments.java | 4 + .../core/ImagePipelineFactory.java | 1 + .../imagepipeline/core/ProducerFactory.java | 13 ++ .../core/ProducerSequenceFactory.java | 46 ++++- .../LocalVideoThumbnailProducer2.java | 190 ++++++++++++++++++ .../imagepipeline/request/ImageRequest.java | 20 +- .../request/ImageRequestBuilder.java | 16 +- 7 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 imagepipeline/src/main/java/com/facebook/imagepipeline/producers/LocalVideoThumbnailProducer2.java diff --git a/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ImagePipelineExperiments.java b/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ImagePipelineExperiments.java index 0a03a00f30..14e85592df 100644 --- a/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ImagePipelineExperiments.java +++ b/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ImagePipelineExperiments.java @@ -21,6 +21,7 @@ import com.facebook.imagepipeline.decoder.ImageDecoder; import com.facebook.imagepipeline.decoder.ProgressiveJpegConfig; import com.facebook.imagepipeline.image.CloseableImage; +import com.facebook.imagepipeline.memory.BitmapPool; import com.facebook.imageutils.BitmapUtil; /** @@ -251,6 +252,7 @@ public interface ProducerFactoryMethod { ProducerFactory createProducerFactory( Context context, + BitmapPool bitmapPool, ByteArrayPool byteArrayPool, ImageDecoder imageDecoder, ProgressiveJpegConfig progressiveJpegConfig, @@ -276,6 +278,7 @@ public static class DefaultProducerFactoryMethod implements ProducerFactoryMetho @Override public ProducerFactory createProducerFactory( Context context, + BitmapPool bitmapPool, ByteArrayPool byteArrayPool, ImageDecoder imageDecoder, ProgressiveJpegConfig progressiveJpegConfig, @@ -296,6 +299,7 @@ public ProducerFactory createProducerFactory( int maxBitmapSize) { return new ProducerFactory( context, + bitmapPool, byteArrayPool, imageDecoder, progressiveJpegConfig, diff --git a/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ImagePipelineFactory.java b/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ImagePipelineFactory.java index 3ba77c0a44..b3e3bc3b9f 100644 --- a/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ImagePipelineFactory.java +++ b/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ImagePipelineFactory.java @@ -349,6 +349,7 @@ private ProducerFactory getProducerFactory() { .getProducerFactoryMethod() .createProducerFactory( mConfig.getContext(), + mConfig.getPoolFactory().getBitmapPool(), mConfig.getPoolFactory().getSmallByteArrayPool(), getImageDecoder(), mConfig.getProgressiveJpegConfig(), diff --git a/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ProducerFactory.java b/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ProducerFactory.java index e9b5671a2e..1d93d9b48f 100644 --- a/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ProducerFactory.java +++ b/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ProducerFactory.java @@ -24,6 +24,7 @@ import com.facebook.imagepipeline.decoder.ProgressiveJpegConfig; import com.facebook.imagepipeline.image.CloseableImage; import com.facebook.imagepipeline.image.EncodedImage; +import com.facebook.imagepipeline.memory.BitmapPool; import com.facebook.imagepipeline.producers.AddImageTransformMetaDataProducer; import com.facebook.imagepipeline.producers.BitmapMemoryCacheGetProducer; import com.facebook.imagepipeline.producers.BitmapMemoryCacheKeyMultiplexProducer; @@ -43,6 +44,7 @@ import com.facebook.imagepipeline.producers.LocalFileFetchProducer; import com.facebook.imagepipeline.producers.LocalResourceFetchProducer; import com.facebook.imagepipeline.producers.LocalVideoThumbnailProducer; +import com.facebook.imagepipeline.producers.LocalVideoThumbnailProducer2; import com.facebook.imagepipeline.producers.NetworkFetchProducer; import com.facebook.imagepipeline.producers.NetworkFetcher; import com.facebook.imagepipeline.producers.NullProducer; @@ -71,6 +73,7 @@ public class ProducerFactory { private AssetManager mAssetManager; // Decode dependencies + private final BitmapPool mBitmapPool; private final ByteArrayPool mByteArrayPool; private final ImageDecoder mImageDecoder; private final ProgressiveJpegConfig mProgressiveJpegConfig; @@ -101,6 +104,7 @@ public class ProducerFactory { public ProducerFactory( Context context, + BitmapPool bitmapPool, ByteArrayPool byteArrayPool, ImageDecoder imageDecoder, ProgressiveJpegConfig progressiveJpegConfig, @@ -123,6 +127,7 @@ public ProducerFactory( mResources = context.getApplicationContext().getResources(); mAssetManager = context.getApplicationContext().getAssets(); + mBitmapPool = bitmapPool; mByteArrayPool = byteArrayPool; mImageDecoder = imageDecoder; mProgressiveJpegConfig = progressiveJpegConfig; @@ -294,6 +299,14 @@ public LocalVideoThumbnailProducer newLocalVideoThumbnailProducer() { mContentResolver); } + public LocalVideoThumbnailProducer2 newLocalVideoThumbnailProducer2() { + return new LocalVideoThumbnailProducer2( + mPooledByteBufferFactory, + mBitmapPool, + mExecutorSupplier.forLocalStorageRead(), + mContentResolver); + } + public NetworkFetchProducer newNetworkFetchProducer(NetworkFetcher networkFetcher) { return new NetworkFetchProducer( mPooledByteBufferFactory, diff --git a/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ProducerSequenceFactory.java b/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ProducerSequenceFactory.java index 15cb9d6f18..84fb20a955 100644 --- a/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ProducerSequenceFactory.java +++ b/imagepipeline/src/main/java/com/facebook/imagepipeline/core/ProducerSequenceFactory.java @@ -82,6 +82,8 @@ public class ProducerSequenceFactory { private Producer mCommonNetworkFetchToEncodedMemorySequence; @VisibleForTesting Producer> mLocalImageFileFetchSequence; @VisibleForTesting Producer> mLocalVideoFileFetchSequence; + @VisibleForTesting Producer> mLocalVideoFileFetchSequence2; + @VisibleForTesting Producer mLocalVideoFileFetchToEncodedMemorySequence; @VisibleForTesting Producer> mLocalContentUriFetchSequence; @VisibleForTesting Producer> mLocalResourceFetchSequence; @VisibleForTesting Producer> mLocalAssetFetchSequence; @@ -279,12 +281,12 @@ private Producer> getBasicDecodedImageSequenc case SOURCE_TYPE_NETWORK: return getNetworkFetchSequence(); case SOURCE_TYPE_LOCAL_VIDEO_FILE: - return getLocalVideoFileFetchSequence(); + return getLocalVideoFileFetchSequence(imageRequest); case SOURCE_TYPE_LOCAL_IMAGE_FILE: return getLocalImageFileFetchSequence(); case SOURCE_TYPE_LOCAL_CONTENT: if (MediaUtils.isVideo(mContentResolver.getType(uri))) { - return getLocalVideoFileFetchSequence(); + return getLocalVideoFileFetchSequence(imageRequest); } return getLocalContentUriFetchSequence(); case SOURCE_TYPE_LOCAL_ASSET: @@ -441,6 +443,14 @@ private synchronized Producer getBackgroundLocalFileFetchToEncodeM return mLocalImageFileFetchSequence; } + + private Producer> + getLocalVideoFileFetchSequence(ImageRequest imageRequest) { + imageRequest.setIsLocalVideoUri(true); + return imageRequest.isVideoThumbnailDiskCacheEnabled() ? + getLocalVideoFileFetchSequence2() : getLocalVideoFileFetchSequence(); + } + /** * Bitmap cache get -> thread hand off -> multiplex -> bitmap cache -> * local video thumbnail @@ -456,6 +466,38 @@ private synchronized Producer getBackgroundLocalFileFetchToEncodeM return mLocalVideoFileFetchSequence; } + /** + * Bitmap cache get -> thread hand off -> multiplex -> bitmap cache -> + * decode -> multiplex -> encoded cache -> disk cache -> (webp transcode) -> local video thumbnail + */ + private synchronized Producer> + getLocalVideoFileFetchSequence2() { + if (mLocalVideoFileFetchSequence2 == null) { + mLocalVideoFileFetchSequence2 = + newBitmapCacheGetToDecodeSequence(getLocalVideoFileFetchToEncodedMemorySequence()); + } + + return mLocalVideoFileFetchSequence2; + } + + /** + * multiplex -> encoded cache -> disk cache -> (webp transcode) -> local video thumbnail. + */ + private synchronized Producer getLocalVideoFileFetchToEncodedMemorySequence() { + FrescoSystrace.beginSection("ProducerSequenceFactory#getLocalVideoFileFetchToEncodedMemorySequence"); + if (mLocalVideoFileFetchToEncodedMemorySequence == null) { + FrescoSystrace.beginSection("ProducerSequenceFactory#getLocalVideoFileFetchToEncodedMemorySequence:init"); + Producer inputProducer = + newEncodedCacheMultiplexToTranscodeSequence( + mProducerFactory.newLocalVideoThumbnailProducer2()); + mLocalVideoFileFetchToEncodedMemorySequence = + ProducerFactory.newAddImageTransformMetaDataProducer(inputProducer); + FrescoSystrace.endSection(); + } + FrescoSystrace.endSection(); + return mLocalVideoFileFetchToEncodedMemorySequence; + } + /** * bitmap cache get -> * background thread hand-off -> multiplex -> bitmap cache -> decode -> diff --git a/imagepipeline/src/main/java/com/facebook/imagepipeline/producers/LocalVideoThumbnailProducer2.java b/imagepipeline/src/main/java/com/facebook/imagepipeline/producers/LocalVideoThumbnailProducer2.java new file mode 100644 index 0000000000..2d1f94a62e --- /dev/null +++ b/imagepipeline/src/main/java/com/facebook/imagepipeline/producers/LocalVideoThumbnailProducer2.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.imagepipeline.producers; + +import android.content.ContentResolver; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.media.ThumbnailUtils; +import android.net.Uri; +import android.os.Build; +import android.provider.DocumentsContract; +import android.provider.MediaStore; +import android.support.annotation.Nullable; +import com.facebook.common.internal.ImmutableMap; +import com.facebook.common.internal.VisibleForTesting; +import com.facebook.common.memory.PooledByteBuffer; +import com.facebook.common.memory.PooledByteBufferFactory; +import com.facebook.common.memory.PooledByteBufferOutputStream; +import com.facebook.common.references.CloseableReference; +import com.facebook.common.util.UriUtil; +import com.facebook.imagepipeline.image.EncodedImage; +import com.facebook.imagepipeline.memory.BitmapPool; +import com.facebook.imagepipeline.request.ImageRequest; +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * A producer that creates video thumbnails. + * + *

Those thumbnails will be transformed into EncodedImage and put into disk cache if need + * + */ +public class LocalVideoThumbnailProducer2 implements + Producer { + + public static final String PRODUCER_NAME = "VideoThumbnailProducer"; + @VisibleForTesting static final String CREATED_THUMBNAIL = "createdThumbnail"; + + private final Executor mExecutor; + private final ContentResolver mContentResolver; + private final PooledByteBufferFactory mPooledByteBufferFactory; + private final BitmapPool mBitmapPool; + + public LocalVideoThumbnailProducer2( + PooledByteBufferFactory pooledByteBufferFactory, + BitmapPool bitmapPool, + Executor executor, + ContentResolver contentResolver) { + mPooledByteBufferFactory = pooledByteBufferFactory; + mBitmapPool = bitmapPool; + mExecutor = executor; + mContentResolver = contentResolver; + } + + @Override + public void produceResults( + final Consumer consumer, + final ProducerContext producerContext) { + + final ProducerListener listener = producerContext.getListener(); + final String requestId = producerContext.getId(); + final ImageRequest imageRequest = producerContext.getImageRequest(); + final StatefulProducerRunnable cancellableProducerRunnable = + new StatefulProducerRunnable( + consumer, + listener, + PRODUCER_NAME, + requestId) { + @Override + protected void onSuccess(EncodedImage result) { + super.onSuccess(result); + listener.onUltimateProducerReached(requestId, PRODUCER_NAME, result != null); + } + + @Override + protected void onFailure(Exception e) { + super.onFailure(e); + listener.onUltimateProducerReached(requestId, PRODUCER_NAME, false); + } + + @Override + protected EncodedImage getResult() throws Exception { + EncodedImage encodedImage = getEncodedImage(imageRequest); + if (encodedImage == null) { + listener.onUltimateProducerReached(requestId, PRODUCER_NAME, false); + return null; + } + encodedImage.parseMetaData(); + listener.onUltimateProducerReached(requestId, PRODUCER_NAME, true); + return encodedImage; + } + + @Override + protected Map getExtraMapOnSuccess( + final EncodedImage result) { + return ImmutableMap.of(CREATED_THUMBNAIL, String.valueOf(result != null)); + } + + @Override + protected void disposeResult(EncodedImage result) { + EncodedImage.closeSafely(result); + } + }; + producerContext.addCallbacks( + new BaseProducerContextCallbacks() { + @Override + public void onCancellationRequested() { + cancellableProducerRunnable.cancel(); + } + }); + mExecutor.execute(cancellableProducerRunnable); + } + + + protected EncodedImage getEncodedImage(ImageRequest imageRequest) { + String path = getLocalFilePath(imageRequest); + if (path == null) { + return null; + } + Bitmap thumbnailBitmap = ThumbnailUtils.createVideoThumbnail( + path, + calculateKind(imageRequest)); + if (thumbnailBitmap == null) { + return null; + } + + PooledByteBufferOutputStream pooledOutputStream = mPooledByteBufferFactory.newOutputStream(); + try { + thumbnailBitmap.compress(thumbnailBitmap.hasAlpha() ? Bitmap.CompressFormat.PNG : Bitmap.CompressFormat.JPEG, + 100, pooledOutputStream); + return getByteBufferBackedEncodedImage(pooledOutputStream); + } finally { + mBitmapPool.release(thumbnailBitmap); + pooledOutputStream.close(); + } + } + + private EncodedImage getByteBufferBackedEncodedImage( + PooledByteBufferOutputStream pooledOutputStream) { + CloseableReference result = null; + try { + result = CloseableReference.of(pooledOutputStream.toByteBuffer()); + return new EncodedImage(result); + } finally { + CloseableReference.closeSafely(result); + } + } + + private static int calculateKind(ImageRequest imageRequest) { + if (imageRequest.getPreferredWidth() > 96 || imageRequest.getPreferredHeight() > 96) { + return MediaStore.Images.Thumbnails.MINI_KIND; + } + return MediaStore.Images.Thumbnails.MICRO_KIND; + } + + @Nullable private String getLocalFilePath(ImageRequest imageRequest) { + Uri uri = imageRequest.getSourceUri(); + if (UriUtil.isLocalFileUri(uri)) { + return imageRequest.getSourceFile().getPath(); + } else if (UriUtil.isLocalContentUri(uri)) { + String selection = null; + String[] selectionArgs = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT + && "com.android.providers.media.documents".equals(uri.getAuthority())) { + String documentId = DocumentsContract.getDocumentId(uri); + uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + selection = MediaStore.Video.Media._ID + "=?"; + selectionArgs = new String[] {documentId.split(":")[1]}; + } + Cursor cursor = + mContentResolver.query( + uri, new String[] {MediaStore.Video.Media.DATA}, selection, selectionArgs, null); + try { + if (cursor != null && cursor.moveToFirst()) { + return cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA)); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + return null; + } +} diff --git a/imagepipeline/src/main/java/com/facebook/imagepipeline/request/ImageRequest.java b/imagepipeline/src/main/java/com/facebook/imagepipeline/request/ImageRequest.java index 5a9ae3dd15..8036a43993 100644 --- a/imagepipeline/src/main/java/com/facebook/imagepipeline/request/ImageRequest.java +++ b/imagepipeline/src/main/java/com/facebook/imagepipeline/request/ImageRequest.java @@ -74,12 +74,18 @@ public class ImageRequest { /** Lowest level that is permitted to fetch an image from */ private final RequestLevel mLowestPermittedRequestLevel; - /** Whether the disk cache should be used for this request */ + /** Whether the disk cache should be used for this request, which is partly dependent on the URI. */ private final boolean mIsDiskCacheEnabled; /** Whether the memory cache should be used for this request */ private final boolean mIsMemoryCacheEnabled; + /** Whether the decoded video thumbnail should be store to local disk image cache */ + private final boolean mIsVideoThumbnailDiskCacheEnabled; + + /** Whether the source uri is local video */ + private boolean mIsLocalVideoUri = false; + /** Postprocessor to run on the output bitmap. */ private final @Nullable Postprocessor mPostprocessor; @@ -117,6 +123,7 @@ protected ImageRequest(ImageRequestBuilder builder) { mLowestPermittedRequestLevel = builder.getLowestPermittedRequestLevel(); mIsDiskCacheEnabled = builder.isDiskCacheEnabled(); mIsMemoryCacheEnabled = builder.isMemoryCacheEnabled(); + mIsVideoThumbnailDiskCacheEnabled = builder.isVideoThumbnailDiskCacheEnabled(); mPostprocessor = builder.getPostprocessor(); @@ -185,7 +192,16 @@ public RequestLevel getLowestPermittedRequestLevel() { } public boolean isDiskCacheEnabled() { - return mIsDiskCacheEnabled; + return mIsDiskCacheEnabled && (UriUtil.isNetworkUri(mSourceUri) + || (mIsVideoThumbnailDiskCacheEnabled && mIsLocalVideoUri)); + } + + public boolean isVideoThumbnailDiskCacheEnabled() { + return mIsDiskCacheEnabled && (mIsVideoThumbnailDiskCacheEnabled && mIsLocalVideoUri); + } + + public void setIsLocalVideoUri(boolean localVideoUri) { + mIsLocalVideoUri = localVideoUri; } public boolean isMemoryCacheEnabled() { diff --git a/imagepipeline/src/main/java/com/facebook/imagepipeline/request/ImageRequestBuilder.java b/imagepipeline/src/main/java/com/facebook/imagepipeline/request/ImageRequestBuilder.java index be010c6a50..a9d76a07c6 100644 --- a/imagepipeline/src/main/java/com/facebook/imagepipeline/request/ImageRequestBuilder.java +++ b/imagepipeline/src/main/java/com/facebook/imagepipeline/request/ImageRequestBuilder.java @@ -41,6 +41,7 @@ public class ImageRequestBuilder { private @Nullable Postprocessor mPostprocessor = null; private boolean mDiskCacheEnabled = true; private boolean mMemoryCacheEnabled = true; + private boolean mVideoThumbnailDiskCacheEnable = true; private @Nullable RequestListener mRequestListener; private @Nullable BytesRange mBytesRange = null; @@ -263,9 +264,20 @@ public ImageRequestBuilder disableDiskCache() { return this; } - /** Returns whether the use of the disk cache is enabled, which is partly dependent on the URI. */ + /** Returns whether the use of the disk cache is enabled */ public boolean isDiskCacheEnabled() { - return mDiskCacheEnabled && UriUtil.isNetworkUri(mSourceUri); + return mDiskCacheEnabled; + } + + /** Disables video thumbnail disk cache for this request if the image come from local video. */ + public ImageRequestBuilder disableVideoThumbnailDiskCache() { + mVideoThumbnailDiskCacheEnable = false; + return this; + } + + /** Return whether the disk cache of local video thumbnails is enabled */ + public boolean isVideoThumbnailDiskCacheEnabled() { + return mVideoThumbnailDiskCacheEnable; } /** Disables memory cache for this request. */ From 19f65aef9bdcf50cb134a6213a01a1b7196948a3 Mon Sep 17 00:00:00 2001 From: zjupure Date: Sat, 25 Aug 2018 22:28:26 +0800 Subject: [PATCH 2/2] Add test for video diskcache to fix CI build failure --- .../ImageRequestBuilderCacheEnabledTest.java | 61 ------------ .../request/ImageRequestCacheEnabledTest.java | 95 +++++++++++++++++++ 2 files changed, 95 insertions(+), 61 deletions(-) delete mode 100644 imagepipeline/src/test/java/com/facebook/imagepipeline/request/ImageRequestBuilderCacheEnabledTest.java create mode 100644 imagepipeline/src/test/java/com/facebook/imagepipeline/request/ImageRequestCacheEnabledTest.java diff --git a/imagepipeline/src/test/java/com/facebook/imagepipeline/request/ImageRequestBuilderCacheEnabledTest.java b/imagepipeline/src/test/java/com/facebook/imagepipeline/request/ImageRequestBuilderCacheEnabledTest.java deleted file mode 100644 index 2d28170607..0000000000 --- a/imagepipeline/src/test/java/com/facebook/imagepipeline/request/ImageRequestBuilderCacheEnabledTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -package com.facebook.imagepipeline.request; - -import static org.junit.Assert.assertEquals; - -import android.net.Uri; -import java.util.Arrays; -import java.util.Collection; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.ParameterizedRobolectricTestRunner; - -@RunWith(ParameterizedRobolectricTestRunner.class) -public class ImageRequestBuilderCacheEnabledTest { - - @ParameterizedRobolectricTestRunner.Parameters(name = "URI of scheme \"{0}://\"") - public static Collection data() { - return Arrays.asList( - new Object[][]{ - {"asset", false}, - {"content", false}, - {"data", false}, - {"file", false}, - {"http", true}, - {"https", true}, - {"res", false}, - }); - } - - private final String mUriScheme; - private final boolean mExpectedDefaultDiskCacheEnabled; - - public ImageRequestBuilderCacheEnabledTest( - String uriScheme, - Boolean expectedDefaultDiskCacheEnabled) { - mUriScheme = uriScheme; - mExpectedDefaultDiskCacheEnabled = expectedDefaultDiskCacheEnabled; - } - - @Test - public void testIsDiskCacheEnabledByDefault() throws Exception { - ImageRequestBuilder imageRequestBuilder = createBuilder(); - assertEquals(mExpectedDefaultDiskCacheEnabled, imageRequestBuilder.isDiskCacheEnabled()); - } - - @Test - public void testIsDiskCacheDisabledIfRequested() throws Exception { - ImageRequestBuilder imageRequestBuilder = createBuilder(); - imageRequestBuilder.disableDiskCache(); - assertEquals(false, imageRequestBuilder.isDiskCacheEnabled()); - } - - private ImageRequestBuilder createBuilder() { - return ImageRequestBuilder.newBuilderWithSource(Uri.parse(mUriScheme + "://request")); - } -} diff --git a/imagepipeline/src/test/java/com/facebook/imagepipeline/request/ImageRequestCacheEnabledTest.java b/imagepipeline/src/test/java/com/facebook/imagepipeline/request/ImageRequestCacheEnabledTest.java new file mode 100644 index 0000000000..5c698d7ddf --- /dev/null +++ b/imagepipeline/src/test/java/com/facebook/imagepipeline/request/ImageRequestCacheEnabledTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package com.facebook.imagepipeline.request; + +import static org.junit.Assert.assertEquals; + +import android.net.Uri; +import java.util.Arrays; +import java.util.Collection; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.ParameterizedRobolectricTestRunner; + +@RunWith(ParameterizedRobolectricTestRunner.class) +public class ImageRequestCacheEnabledTest { + + @ParameterizedRobolectricTestRunner.Parameters(name = "URI of scheme \"{0}://\"") + public static Collection data() { + return Arrays.asList( + new Object[][]{ + {"asset", false, false, false}, + {"content", false, false, false}, + {"content", true, true, true}, + {"data", false, false, false}, + {"file", false, false, false}, + {"file", true, true, true}, + {"http", false, true, false}, + {"https", false, true, false}, + {"res", false, false, false}, + }); + } + + private final String mUriScheme; + private final boolean mIsNetworkUrl; + private final boolean mIsLocalVideoUrl; + private final boolean mExpectedDefaultDiskCacheEnabled; + private final boolean mExpectedDefaultLocalVideoDiskCacheEnabled; + + public ImageRequestCacheEnabledTest( + String uriScheme, + Boolean isLocalVideoUrl, + Boolean expectedDefaultDiskCacheEnabled, + Boolean expectedDefaultLocalVideoDiskCacheEnabled) { + mUriScheme = uriScheme; + mIsNetworkUrl = "http".equals(mUriScheme) || "https".equals(mUriScheme); + mIsLocalVideoUrl = isLocalVideoUrl; + mExpectedDefaultDiskCacheEnabled = expectedDefaultDiskCacheEnabled; + mExpectedDefaultLocalVideoDiskCacheEnabled = expectedDefaultLocalVideoDiskCacheEnabled; + } + + @Test + public void testIsDiskCacheEnabledByDefault() throws Exception { + ImageRequest imageRequest = createRequest(false, false); + assertEquals(mExpectedDefaultDiskCacheEnabled, imageRequest.isDiskCacheEnabled()); + assertEquals(mExpectedDefaultLocalVideoDiskCacheEnabled, imageRequest.isVideoThumbnailDiskCacheEnabled()); + } + + @Test + public void testIsDiskCacheDisabledIfRequested() throws Exception { + ImageRequest imageRequest = createRequest(true, false); + assertEquals(false, imageRequest.isDiskCacheEnabled()); + assertEquals(false, imageRequest.isVideoThumbnailDiskCacheEnabled()); + // disable local video disk cache + imageRequest = createRequest(true, true); + assertEquals(false, imageRequest.isDiskCacheEnabled()); + assertEquals(false, imageRequest.isVideoThumbnailDiskCacheEnabled()); + } + + @Test + public void testIsLocalVideoCacheDisabledIfRequested() throws Exception { + ImageRequest imageRequest = createRequest(false, true); + assertEquals(mExpectedDefaultDiskCacheEnabled && mIsNetworkUrl, imageRequest.isDiskCacheEnabled()); + assertEquals(false, imageRequest.isVideoThumbnailDiskCacheEnabled()); + } + + + private ImageRequest createRequest( + boolean disableDiskCache, + boolean disableLocalVideoDiskCache) { + ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(mUriScheme + "://request/12345")); + if (disableDiskCache) { + builder = builder.disableDiskCache(); + } + if (disableLocalVideoDiskCache) { + builder.disableVideoThumbnailDiskCache(); + } + ImageRequest request = builder.build(); + request.setIsLocalVideoUri(mIsLocalVideoUrl); + return request; + } +}