/* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.imagepipeline.request; import javax.annotation.Nullable; import android.net.Uri; import com.facebook.common.internal.Preconditions; import com.facebook.common.util.UriUtil; import com.facebook.imagepipeline.common.ImageDecodeOptions; import com.facebook.imagepipeline.common.Priority; import com.facebook.imagepipeline.common.ResizeOptions; import com.facebook.imagepipeline.common.RotationOptions; import com.facebook.imagepipeline.core.ImagePipelineConfig; import com.facebook.imagepipeline.listener.RequestListener; import static com.facebook.imagepipeline.request.ImageRequest.CacheChoice; import static com.facebook.imagepipeline.request.ImageRequest.RequestLevel; /** * Builder class for {@link ImageRequest}s. */ public class ImageRequestBuilder { private Uri mSourceUri = null; private RequestLevel mLowestPermittedRequestLevel = RequestLevel.FULL_FETCH; private @Nullable ResizeOptions mResizeOptions = null; private @Nullable RotationOptions mRotationOptions = null; private ImageDecodeOptions mImageDecodeOptions = ImageDecodeOptions.defaults(); private CacheChoice mCacheChoice = CacheChoice.DEFAULT; private boolean mProgressiveRenderingEnabled = ImagePipelineConfig.getDefaultImageRequestConfig().isProgressiveRenderingEnabled(); private boolean mLocalThumbnailPreviewsEnabled = false; private Priority mRequestPriority = Priority.HIGH; private @Nullable Postprocessor mPostprocessor = null; private boolean mDiskCacheEnabled = true; private @Nullable RequestListener mRequestListener; private @Nullable MediaVariations mMediaVariations = null; /** * Creates a new request builder instance. The setting will be done according to the source type. * @param uri the uri to fetch * @return a new request builder instance */ public static ImageRequestBuilder newBuilderWithSource(Uri uri) { return new ImageRequestBuilder().setSource(uri); } /** * Creates a new request builder instance for a local resource image. * * <p>Only image resources can be used with the image pipeline (PNG, JPG, GIF). Other resource * types such as Strings or XML Drawables make no sense in the context of the image pipeline and * so cannot be supported. Attempts to do so will throw an * {@link java.lang.IllegalArgumentException} when the pipeline tries to decode the resource. * * <p>One potentially confusing case is drawable declared in XML (e.g. ShapeDrawable). This is not * an image. If you want to display an XML drawable as the main image, then set it as a * placeholder and do not set a URI. * <p/> * * @param resId local image resource id. * @return a new request builder instance. */ public static ImageRequestBuilder newBuilderWithResourceId(int resId) { return newBuilderWithSource(UriUtil.getUriForResourceId(resId)); } /** * Creates a new request builder instance with the same parameters as the imageRequest passed in. * @param imageRequest the ImageRequest from where to copy the parameters to the builder. * @return a new request builder instance */ public static ImageRequestBuilder fromRequest(ImageRequest imageRequest) { return ImageRequestBuilder.newBuilderWithSource(imageRequest.getSourceUri()) .setImageDecodeOptions(imageRequest.getImageDecodeOptions()) .setCacheChoice(imageRequest.getCacheChoice()) .setLocalThumbnailPreviewsEnabled(imageRequest.getLocalThumbnailPreviewsEnabled()) .setLowestPermittedRequestLevel(imageRequest.getLowestPermittedRequestLevel()) .setMediaVariations(imageRequest.getMediaVariations()) .setPostprocessor(imageRequest.getPostprocessor()) .setProgressiveRenderingEnabled(imageRequest.getProgressiveRenderingEnabled()) .setRequestPriority(imageRequest.getPriority()) .setResizeOptions(imageRequest.getResizeOptions()) .setRequestListener(imageRequest.getRequestListener()) .setRotationOptions(imageRequest.getRotationOptions()); } private ImageRequestBuilder() { } /** * Sets the source uri (both network and local uris are supported). * Note: this will enable disk caching for network sources, and disable it for local sources. * @param uri the uri to fetch the image from * @return the updated builder instance */ public ImageRequestBuilder setSource(Uri uri) { Preconditions.checkNotNull(uri); mSourceUri = uri; return this; } /** Gets the source Uri. */ public Uri getSourceUri() { return mSourceUri; } /** * Sets details of variations of the piece of media which might allow the request to be satisfied * (either as a placeholder or ultimate result) by a cached image at another size. * * <p><i>Experimental.</i> This is now functional but the behaviour is still being tested. * @param mediaVariations the variations of image which relate to the same original media * @return the updated builder instance */ public ImageRequestBuilder setMediaVariations(MediaVariations mediaVariations) { mMediaVariations = mediaVariations; return this; } /** * Sets a media ID for variations of the piece of media which might allow the request to be * satisfied (either as a placeholder or ultimate result) by a cached image at another size. * * <p><i>Experimental.</i> This is now functional but the behaviour is still being tested. * @see #setMediaVariations(MediaVariations) * @param mediaId the unique ID for this piece of media. This must be non-null and unique for * this piece of media (i.e. another request for the same picture at a different * size should share the ID but not an unrelated image and not the same media at * a different orientation). * @return the updated builder instance */ public ImageRequestBuilder setMediaVariationsForMediaId(String mediaId) { return setMediaVariations(MediaVariations.forMediaId(mediaId)); } public @Nullable MediaVariations getMediaVariations() { return mMediaVariations; } /** * Sets the lowest level that is permitted to request the image from. * @param requestLevel the lowest request level that is allowed * @return the updated builder instance */ public ImageRequestBuilder setLowestPermittedRequestLevel(RequestLevel requestLevel) { mLowestPermittedRequestLevel = requestLevel; return this; } /** Gets the lowest permitted request level. */ public RequestLevel getLowestPermittedRequestLevel() { return mLowestPermittedRequestLevel; } /** * Enables or disables auto-rotate for the image in case image has orientation. * @return the updated builder instance * @param enabled * @deprecated Use #setRotationOptions(RotationOptions) */ @Deprecated public ImageRequestBuilder setAutoRotateEnabled(boolean enabled) { if (enabled) { return setRotationOptions(RotationOptions.autoRotate()); } else { return setRotationOptions(RotationOptions.disableRotation()); } } /** * Sets resize options in case resize should be performed. * @param resizeOptions resize options * @return the modified builder instance */ public ImageRequestBuilder setResizeOptions(@Nullable ResizeOptions resizeOptions) { mResizeOptions = resizeOptions; return this; } /** Gets the resize options if set, null otherwise. */ public @Nullable ResizeOptions getResizeOptions() { return mResizeOptions; } /** * Sets rotation options for the image, whether to rotate by a multiple of 90 degrees, use the * EXIF metadata (relevant to JPEGs only) or to not rotate. This also specifies whether the * rotation should be left until the bitmap is rendered (as the GPU can do this more efficiently * than the effort to change the bitmap object). * * @param rotationOptions rotation options * @return the modified builder instance */ public ImageRequestBuilder setRotationOptions(@Nullable RotationOptions rotationOptions) { mRotationOptions = rotationOptions; return this; } /** Gets the rotation options if set, null otherwise. */ public @Nullable RotationOptions getRotationOptions() { return mRotationOptions; } public ImageRequestBuilder setImageDecodeOptions(ImageDecodeOptions imageDecodeOptions) { mImageDecodeOptions = imageDecodeOptions; return this; } public ImageDecodeOptions getImageDecodeOptions() { return mImageDecodeOptions; } /** * Sets the cache option. Pipeline might use different caches and eviction policies for each * image type. * @param cacheChoice the cache choice to set * @return the modified builder instance */ public ImageRequestBuilder setCacheChoice(ImageRequest.CacheChoice cacheChoice) { mCacheChoice = cacheChoice; return this; } /** Gets the cache choice (profile image or default). */ public CacheChoice getCacheChoice() { return mCacheChoice; } /** * Enables or disables progressive rendering. * @param enabled * @return the modified builder instance */ public ImageRequestBuilder setProgressiveRenderingEnabled(boolean enabled) { mProgressiveRenderingEnabled = enabled; return this; } /** Returns whether progressive loading is enabled. */ public boolean isProgressiveRenderingEnabled() { return mProgressiveRenderingEnabled; } /** * Enables or disables the use of local thumbnails as previews. * @param enabled * @return the modified builder instance */ public ImageRequestBuilder setLocalThumbnailPreviewsEnabled(boolean enabled) { mLocalThumbnailPreviewsEnabled = enabled; return this; } /** Returns whether the use of local thumbnails for previews is enabled. */ public boolean isLocalThumbnailPreviewsEnabled() { return mLocalThumbnailPreviewsEnabled; } /** Disables disk cache for this request, regardless where the image will come from. */ public ImageRequestBuilder disableDiskCache() { mDiskCacheEnabled = false; return this; } /** Returns whether the use of the disk cache is enabled, which is partly dependent on the URI. */ public boolean isDiskCacheEnabled() { return mDiskCacheEnabled && UriUtil.isNetworkUri(mSourceUri); } /** * Set priority for the request. * @param requestPriority * @return the modified builder instance */ public ImageRequestBuilder setRequestPriority(Priority requestPriority) { mRequestPriority = requestPriority; return this; } /** Returns the request priority. */ public Priority getRequestPriority() { return mRequestPriority; } /** * Sets the postprocessor. * @param postprocessor postprocessor to postprocess the output bitmap with. * @return the modified builder instance */ public ImageRequestBuilder setPostprocessor(Postprocessor postprocessor) { mPostprocessor = postprocessor; return this; } /** Gets postprocessor if set, null otherwise. */ public @Nullable Postprocessor getPostprocessor() { return mPostprocessor; } /** * Sets a request listener to use for just this image request * * @param requestListener a request listener to use in addition to the global ones set in the * {@link com.facebook.imagepipeline.core.ImagePipelineConfig} * @return the modified builder instance */ public ImageRequestBuilder setRequestListener(RequestListener requestListener) { mRequestListener = requestListener; return this; } /** * @return the additional request listener to use for this image request */ public @Nullable RequestListener getRequestListener() { return mRequestListener; } /** * Builds the Request. * @return a valid image request */ public ImageRequest build() { validate(); return new ImageRequest(this); } /** An exception class for builder methods. */ public static class BuilderException extends RuntimeException { public BuilderException(String message) { super("Invalid request builder: " + message); } } /** Performs validation. */ protected void validate() { // make sure that the source uri is set correctly. if (mSourceUri == null) { throw new BuilderException("Source must be set!"); } // For local resource we require caller to specify statically generated resource id as a path. if (UriUtil.isLocalResourceUri(mSourceUri)) { if (!mSourceUri.isAbsolute()) { throw new BuilderException("Resource URI path must be absolute."); } if (mSourceUri.getPath().isEmpty()) { throw new BuilderException("Resource URI must not be empty"); } try { Integer.parseInt(mSourceUri.getPath().substring(1)); } catch (NumberFormatException ignored) { throw new BuilderException("Resource URI path must be a resource id."); } } // For local asset we require caller to specify absolute path of an asset, which will be // resolved by AssetManager relative to configured asset folder of an app. if (UriUtil.isLocalAssetUri(mSourceUri) && !mSourceUri.isAbsolute()) { throw new BuilderException("Asset URI path must be absolute."); } } }