package com.bumptech.glide.request; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.bumptech.glide.Priority; import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.load.Key; import com.bumptech.glide.load.Option; import com.bumptech.glide.load.Options; import com.bumptech.glide.load.Transformation; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.bitmap.BitmapDrawableTransformation; import com.bumptech.glide.load.resource.bitmap.BitmapEncoder; import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.bumptech.glide.load.resource.bitmap.CenterInside; import com.bumptech.glide.load.resource.bitmap.CircleCrop; import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy; import com.bumptech.glide.load.resource.bitmap.Downsampler; import com.bumptech.glide.load.resource.bitmap.FitCenter; import com.bumptech.glide.load.resource.bitmap.VideoBitmapDecoder; import com.bumptech.glide.load.resource.gif.ByteBufferGifDecoder; import com.bumptech.glide.load.resource.gif.GifDrawable; import com.bumptech.glide.load.resource.gif.GifDrawableTransformation; import com.bumptech.glide.load.resource.gif.StreamGifDecoder; import com.bumptech.glide.signature.EmptySignature; import com.bumptech.glide.util.Preconditions; import com.bumptech.glide.util.Util; import java.util.HashMap; import java.util.Map; /** * Provides type independent options to customize loads with Glide. */ @SuppressWarnings({"PMD.UseUtilityClass", "unused"}) public class RequestOptions implements Cloneable { private static final int UNSET = -1; private static final int SIZE_MULTIPLIER = 1 << 1; private static final int DISK_CACHE_STRATEGY = 1 << 2; private static final int PRIORITY = 1 << 3; private static final int ERROR_PLACEHOLDER = 1 << 4; private static final int ERROR_ID = 1 << 5; private static final int PLACEHOLDER = 1 << 6; private static final int PLACEHOLDER_ID = 1 << 7; private static final int IS_CACHEABLE = 1 << 8; private static final int OVERRIDE = 1 << 9; private static final int SIGNATURE = 1 << 10; private static final int TRANSFORMATION = 1 << 11; private static final int RESOURCE_CLASS = 1 << 12; private static final int FALLBACK = 1 << 13; private static final int FALLBACK_ID = 1 << 14; private static final int THEME = 1 << 15; private static final int TRANSFORMATION_ALLOWED = 1 << 16; private static final int TRANSFORMATION_REQUIRED = 1 << 17; private static final int USE_UNLIMITED_SOURCE_GENERATORS_POOL = 1 << 18; private static final int ONLY_RETRIEVE_FROM_CACHE = 1 << 19; private static RequestOptions skipMemoryCacheTrueOptions; private static RequestOptions skipMemoryCacheFalseOptions; private static RequestOptions fitCenterOptions; private static RequestOptions centerInsideOptions; private static RequestOptions centerCropOptions; private static RequestOptions circleCropOptions; private static RequestOptions noTransformOptions; private static RequestOptions noAnimationOptions; private int fields; private float sizeMultiplier = 1f; private DiskCacheStrategy diskCacheStrategy = DiskCacheStrategy.AUTOMATIC; private Priority priority = Priority.NORMAL; private Drawable errorPlaceholder; private int errorId; private Drawable placeholderDrawable; private int placeholderId; private boolean isCacheable = true; private int overrideHeight = RequestOptions.UNSET; private int overrideWidth = RequestOptions.UNSET; private Key signature = EmptySignature.obtain(); private boolean isTransformationRequired; private boolean isTransformationAllowed = true; private Drawable fallbackDrawable; private int fallbackId; private Options options = new Options(); private Map<Class<?>, Transformation<?>> transformations = new HashMap<>(); private Class<?> resourceClass = Object.class; private boolean isLocked; private Resources.Theme theme; private boolean isAutoCloneEnabled; private boolean useUnlimitedSourceGeneratorsPool; private boolean onlyRetrieveFromCache; /** * Returns a {@link RequestOptions} object with {@link #sizeMultiplier(float)} set. */ public static RequestOptions sizeMultiplierOf(float sizeMultiplier) { return new RequestOptions().sizeMultiplier(sizeMultiplier); } /** * Returns a {@link RequestOptions} object with {@link #sizeMultiplier(float)} set. */ public static RequestOptions diskCacheStrategyOf(@NonNull DiskCacheStrategy diskCacheStrategy) { return new RequestOptions().diskCacheStrategy(diskCacheStrategy); } /** * Returns a {@link RequestOptions} object with {@link #priority(Priority)}} set. */ public static RequestOptions priorityOf(@NonNull Priority priority) { return new RequestOptions().priority(priority); } /** * Returns a {@link RequestOptions} object with {@link #placeholder(Drawable)} set. */ public static RequestOptions placeholderOf(@Nullable Drawable placeholder) { return new RequestOptions().placeholder(placeholder); } /** * Returns a {@link RequestOptions} object with {@link #placeholder(int)} set. */ public static RequestOptions placeholderOf(int placeholderId) { return new RequestOptions().placeholder(placeholderId); } /** * Returns a {@link RequestOptions} object with {@link #error(Drawable)} set. */ public static RequestOptions errorOf(@Nullable Drawable errorDrawable) { return new RequestOptions().error(errorDrawable); } /** * Returns a {@link RequestOptions} object with {@link #error(int)}} set. */ public static RequestOptions errorOf(int errorId) { return new RequestOptions().error(errorId); } /** * Returns a {@link RequestOptions} object with {@link #skipMemoryCache(boolean)} set. */ public static RequestOptions skipMemoryCacheOf(boolean skipMemoryCache) { if (skipMemoryCache) { if (skipMemoryCacheTrueOptions == null) { skipMemoryCacheTrueOptions = new RequestOptions().skipMemoryCache(true).autoClone(); } return skipMemoryCacheTrueOptions; } else { if (skipMemoryCacheFalseOptions == null) { skipMemoryCacheFalseOptions = new RequestOptions().skipMemoryCache(false).autoClone(); } return skipMemoryCacheFalseOptions; } } /** * Returns a {@link RequestOptions} object with {@link #override(int, int)}} set. */ public static RequestOptions overrideOf(int width, int height) { return new RequestOptions().override(width, height); } /** * Returns a {@link RequestOptions} with {@link #override(int, int)} set where both the width and * height are the given size. */ public static RequestOptions overrideOf(int size) { return overrideOf(size, size); } /** * Returns a {@link RequestOptions} object with {@link #signature} set. */ public static RequestOptions signatureOf(@NonNull Key signature) { return new RequestOptions().signature(signature); } /** * Returns a {@link RequestOptions} object with {@link #fitCenter()} set. */ public static RequestOptions fitCenterTransform() { if (fitCenterOptions == null) { fitCenterOptions = new RequestOptions() .fitCenter() .autoClone(); } return fitCenterOptions; } /** * Returns a {@link RequestOptions} object with {@link #centerInside()} set. */ public static RequestOptions centerInsideTransform() { if (centerInsideOptions == null) { centerInsideOptions = new RequestOptions() .centerInside() .autoClone(); } return centerInsideOptions; } /** * Returns a {@link RequestOptions} object with {@link #centerCrop()} set. */ public static RequestOptions centerCropTransform() { if (centerCropOptions == null) { centerCropOptions = new RequestOptions() .centerCrop() .autoClone(); } return centerCropOptions; } /** * Returns a {@link RequestOptions} object with {@link RequestOptions#circleCrop()} set. */ public static RequestOptions circleCropTransform() { if (circleCropOptions == null) { circleCropOptions = new RequestOptions() .circleCrop() .autoClone(); } return circleCropOptions; } /** * Returns a {@link RequestOptions} object with {@link #transform(Transformation)} set. * * @deprecated Use {@link #bitmapTransform(Transformation)}. */ @Deprecated public static RequestOptions bitmapTransform( Context context, @NonNull Transformation<Bitmap> transformation) { return bitmapTransform(transformation); } /** * Returns a {@link RequestOptions} object with {@link #transform(Transformation)} set. */ public static RequestOptions bitmapTransform(@NonNull Transformation<Bitmap> transformation) { return new RequestOptions().transform(transformation); } /** * Returns a {@link RequestOptions} object with {@link #dontTransform()} set. * * @deprecated use {@link #noTransformation()} */ @Deprecated public static RequestOptions noTransform() { return noTransformation(); } /** * Returns a {@link RequestOptions} object with {@link #dontTransform()} set. */ public static RequestOptions noTransformation() { if (noTransformOptions == null) { noTransformOptions = new RequestOptions() .dontTransform() .autoClone(); } return noTransformOptions; } /** * Returns a {@link RequestOptions} object with the given {@link Option} set via * {@link #set(Option, Object)}. */ public static <T> RequestOptions option(@NonNull Option<T> option, @NonNull T value) { return new RequestOptions().set(option, value); } /** * Returns a {@link RequestOptions} object with {@link #decode(Class)} set. */ public static RequestOptions decodeTypeOf(@NonNull Class<?> resourceClass) { return new RequestOptions().decode(resourceClass); } /** * Returns a {@link RequestOptions} object with {@link #format(DecodeFormat)} set. */ public static RequestOptions formatOf(@NonNull DecodeFormat format) { return new RequestOptions().format(format); } /** * Returns a {@link RequestOptions} object with {@link #frame(long)} set. */ public static RequestOptions frameOf(long frameTimeMicros) { return new RequestOptions().frame(frameTimeMicros); } /** * Returns a {@link RequestOptions} object with {@link #downsample(DownsampleStrategy)} set. */ public static RequestOptions downsampleOf(@NonNull DownsampleStrategy strategy) { return new RequestOptions().downsample(strategy); } /** * Returns a {@link com.bumptech.glide.request.RequestOptions} with {@link * #encodeQuality(int)} called with the given quality. */ public static RequestOptions encodeQualityOf(int quality) { return new RequestOptions().encodeQuality(quality); } /** * Returns a {@link com.bumptech.glide.request.RequestOptions} with {@link * #encodeFormat(android.graphics.Bitmap.CompressFormat)} called with the given format. */ public static RequestOptions encodeFormatOf(@NonNull Bitmap.CompressFormat format) { return new RequestOptions().encodeFormat(format); } /** * Returns a new {@link com.bumptech.glide.request.RequestOptions} with {@link #dontAnimate()} * called. */ public static RequestOptions noAnimation() { if (noAnimationOptions == null) { noAnimationOptions = new RequestOptions() .dontAnimate() .autoClone(); } return noAnimationOptions; } private static boolean isSet(int fields, int flag) { return (fields & flag) != 0; } /** * Applies a multiplier to the {@link com.bumptech.glide.request.target.Target}'s size before * loading the resource. Useful for loading thumbnails or trying to avoid loading huge resources * (particularly {@link Bitmap}s on devices with overly dense screens. * * @param sizeMultiplier The multiplier to apply to the * {@link com.bumptech.glide.request.target.Target}'s dimensions when * loading the resource. * @return This request builder. */ public RequestOptions sizeMultiplier(float sizeMultiplier) { if (isAutoCloneEnabled) { return clone().sizeMultiplier(sizeMultiplier); } if (sizeMultiplier < 0f || sizeMultiplier > 1f) { throw new IllegalArgumentException("sizeMultiplier must be between 0 and 1"); } this.sizeMultiplier = sizeMultiplier; fields |= SIZE_MULTIPLIER; return selfOrThrowIfLocked(); } public RequestOptions useUnlimitedSourceGeneratorsPool(boolean flag) { if (isAutoCloneEnabled) { return clone().useUnlimitedSourceGeneratorsPool(flag); } this.useUnlimitedSourceGeneratorsPool = flag; fields |= USE_UNLIMITED_SOURCE_GENERATORS_POOL; return selfOrThrowIfLocked(); } /** * If set to true, will only load an item if found in the cache, and will not fetch from source. */ public RequestOptions onlyRetrieveFromCache(boolean flag) { if (isAutoCloneEnabled) { return clone().onlyRetrieveFromCache(flag); } this.onlyRetrieveFromCache = flag; fields |= ONLY_RETRIEVE_FROM_CACHE; return selfOrThrowIfLocked(); } /** * Sets the {@link DiskCacheStrategy} to use for this load. * * <p> Defaults to {@link DiskCacheStrategy#AUTOMATIC}. </p> * * <p> For most applications {@link DiskCacheStrategy#RESOURCE} is * ideal. Applications that use the same resource multiple times in multiple sizes and are willing * to trade off some speed and disk space in return for lower bandwidth usage may want to consider * using {@link DiskCacheStrategy#DATA} or * {@link DiskCacheStrategy#ALL}. </p> * * @param strategy The strategy to use. * @return This request builder. */ public RequestOptions diskCacheStrategy(@NonNull DiskCacheStrategy strategy) { if (isAutoCloneEnabled) { return clone().diskCacheStrategy(strategy); } this.diskCacheStrategy = Preconditions.checkNotNull(strategy); fields |= DISK_CACHE_STRATEGY; return selfOrThrowIfLocked(); } /** * Sets the priority for this load. * * @param priority A priority. * @return This request builder. */ public RequestOptions priority(@NonNull Priority priority) { if (isAutoCloneEnabled) { return clone().priority(priority); } this.priority = Preconditions.checkNotNull(priority); fields |= PRIORITY; return selfOrThrowIfLocked(); } /** * Sets an {@link Drawable} to display while a resource is loading. * * @param drawable The drawable to display as a placeholder. * @return This request builder. */ public RequestOptions placeholder(@Nullable Drawable drawable) { if (isAutoCloneEnabled) { return clone().placeholder(drawable); } this.placeholderDrawable = drawable; fields |= PLACEHOLDER; return selfOrThrowIfLocked(); } /** * Sets an Android resource id for a {@link Drawable} resource to * display while a resource is loading. * * @param resourceId The id of the resource to use as a placeholder * @return This request builder. */ public RequestOptions placeholder(int resourceId) { if (isAutoCloneEnabled) { return clone().placeholder(resourceId); } this.placeholderId = resourceId; fields |= PLACEHOLDER_ID; return selfOrThrowIfLocked(); } /** * Sets an {@link Drawable} to display if the model provided to * {@link com.bumptech.glide.RequestBuilder#load(Object)} is {@code null}. * * <p> If a fallback is not set, null models will cause the error drawable to be displayed. If the * error drawable is not set, the placeholder will be displayed. * * @see #placeholder(Drawable) * @see #placeholder(int) * * @param drawable The drawable to display as a placeholder. * @return This request builder. */ public RequestOptions fallback(Drawable drawable) { if (isAutoCloneEnabled) { return clone().fallback(drawable); } this.fallbackDrawable = drawable; fields |= FALLBACK; return selfOrThrowIfLocked(); } /** * Sets a resource to display if the model provided to * {@link com.bumptech.glide.RequestBuilder#load(Object)} is {@code null}. * * <p> If a fallback is not set, null models will cause the error drawable to be displayed. If * the error drawable is not set, the placeholder will be displayed. * * @see #placeholder(Drawable) * @see #placeholder(int) * * @param resourceId The id of the resource to use as a fallback. * @return This request builder. */ public RequestOptions fallback(int resourceId) { if (isAutoCloneEnabled) { return clone().fallback(resourceId); } this.fallbackId = resourceId; fields |= FALLBACK_ID; return selfOrThrowIfLocked(); } /** * Sets a {@link Drawable} to display if a load fails. * * @param drawable The drawable to display. * @return This request builder. */ public RequestOptions error(@Nullable Drawable drawable) { if (isAutoCloneEnabled) { return clone().error(drawable); } this.errorPlaceholder = drawable; fields |= ERROR_PLACEHOLDER; return selfOrThrowIfLocked(); } /** * Sets a resource to display if a load fails. * * @param resourceId The id of the resource to use as a placeholder. * @return This request builder. */ public RequestOptions error(int resourceId) { if (isAutoCloneEnabled) { return clone().error(resourceId); } this.errorId = resourceId; fields |= ERROR_ID; return selfOrThrowIfLocked(); } /** * Sets the {@link android.content.res.Resources.Theme} to apply when loading {@link Drawable}s * for resource ids provided via {@link #error(int)}, {@link #placeholder(int)}, and * {@link #fallback(Drawable)}. * * @param theme The theme to use when loading Drawables. * @return this request builder. */ public RequestOptions theme(Resources.Theme theme) { if (isAutoCloneEnabled) { return clone().theme(theme); } this.theme = theme; fields |= THEME; return selfOrThrowIfLocked(); } /** * Allows the loaded resource to skip the memory cache. * * <p> Note - this is not a guarantee. If a request is already pending for this resource and that * request is not also skipping the memory cache, the resource will be cached in memory.</p> * * @param skip True to allow the resource to skip the memory cache. * @return This request builder. */ public RequestOptions skipMemoryCache(boolean skip) { if (isAutoCloneEnabled) { return clone().skipMemoryCache(true); } this.isCacheable = !skip; fields |= IS_CACHEABLE; return selfOrThrowIfLocked(); } /** * Overrides the {@link com.bumptech.glide.request.target.Target}'s width and height with the * given values. This is useful for thumbnails, and should only be used for other cases when you * need a very specific image size. * * @param width The width in pixels to use to load the resource. * @param height The height in pixels to use to load the resource. * @return This request builder. */ public RequestOptions override(int width, int height) { if (isAutoCloneEnabled) { return clone().override(width, height); } this.overrideWidth = width; this.overrideHeight = height; fields |= OVERRIDE; return selfOrThrowIfLocked(); } /** * Overrides the {@link com.bumptech.glide.request.target.Target}'s width and height with the * given size. * * @see #override(int, int) * @param size The width and height to use. * @return This request builder. */ public RequestOptions override(int size) { return override(size, size); } /** * Sets some additional data to be mixed in to the memory and disk cache keys allowing the caller * more control over when cached data is invalidated. * * <p> Note - The signature does not replace the cache key, it is purely additive. </p> * * @param signature A unique non-null {@link Key} representing the current * state of the model that will be mixed in to the cache key. * @return This request builder. * @see com.bumptech.glide.signature.ObjectKey */ public RequestOptions signature(@NonNull Key signature) { if (isAutoCloneEnabled) { return clone().signature(signature); } this.signature = Preconditions.checkNotNull(signature); fields |= SIGNATURE; return selfOrThrowIfLocked(); } /** * Returns a copy of this request builder with all of the options put so far on this builder. * * <p> This method returns a "deep" copy in that all non-immutable arguments are copied such that * changes to one builder will not affect the other builder. However, in addition to immutable * arguments, the current model is not copied copied so changes to the model will affect both * builders. </p> * * <p> Even if this object was locked, the cloned object returned from this method will not be * locked. </p> */ @SuppressWarnings("unchecked") @Override public RequestOptions clone() { try { RequestOptions result = (RequestOptions) super.clone(); result.options = new Options(); result.options.putAll(options); result.transformations = new HashMap<>(); result.transformations.putAll(transformations); result.isLocked = false; result.isAutoCloneEnabled = false; return (RequestOptions) result; } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } public <T> RequestOptions set(@NonNull Option<T> option, @NonNull T value) { if (isAutoCloneEnabled) { return clone().set(option, value); } Preconditions.checkNotNull(option); Preconditions.checkNotNull(value); options.set(option, value); return selfOrThrowIfLocked(); } public RequestOptions decode(@NonNull Class<?> resourceClass) { if (isAutoCloneEnabled) { return clone().decode(resourceClass); } this.resourceClass = Preconditions.checkNotNull(resourceClass); fields |= RESOURCE_CLASS; return selfOrThrowIfLocked(); } public final boolean isTransformationAllowed() { return isTransformationAllowed; } public final boolean isTransformationSet() { return isSet(TRANSFORMATION); } public final boolean isLocked() { return isLocked; } /** * Sets the value for key * {@link com.bumptech.glide.load.resource.bitmap.BitmapEncoder#COMPRESSION_FORMAT}. */ public RequestOptions encodeFormat(@NonNull Bitmap.CompressFormat format) { return set(BitmapEncoder.COMPRESSION_FORMAT, Preconditions.checkNotNull(format)); } /** * Sets the value for key * {@link BitmapEncoder#COMPRESSION_QUALITY}. */ public RequestOptions encodeQuality(int quality) { return set(BitmapEncoder.COMPRESSION_QUALITY, quality); } /** * Sets the {@link DecodeFormat} to use when decoding {@link Bitmap} objects using * {@link Downsampler}. * * <p>{@link DecodeFormat} is a request, not a requirement. It's possible the resource will be * decoded using a decoder that cannot control the format * ({@link android.media.MediaMetadataRetriever} for example), or that the decoder may choose to * ignore the requested format if it can't display the image (i.e. RGB_565 is requested, but the * image has alpha). */ public RequestOptions format(@NonNull DecodeFormat format) { return set(Downsampler.DECODE_FORMAT, Preconditions.checkNotNull(format)); } /** * Sets the time position of the frame to extract from a video. * * @param frameTimeMicros The time position in microseconds of the desired frame. If negative, the * Android framework implementation return a representative frame. */ public RequestOptions frame(long frameTimeMicros) { return set(VideoBitmapDecoder.TARGET_FRAME, frameTimeMicros); } /** * Sets the {@link DownsampleStrategy} to use when decoding {@link Bitmap Bitmaps} using * {@link Downsampler}. */ public RequestOptions downsample(@NonNull DownsampleStrategy strategy) { return set(Downsampler.DOWNSAMPLE_STRATEGY, Preconditions.checkNotNull(strategy)); } /** * Applies {@link com.bumptech.glide.load.resource.bitmap.CenterCrop} to all default types, and * ignores unknown types. * * <p>This will override previous calls to {@link #dontTransform()}. * * @see #optionalTransform(Class, Transformation) * @see #centerCrop() */ public RequestOptions optionalCenterCrop() { return optionalTransform(DownsampleStrategy.CENTER_OUTSIDE, new CenterCrop()); } /** * Applies {@link CenterCrop} to all default types and * throws an exception if asked to transform an unknown type. * * <p>this will override previous calls to {@link #dontTransform()}. * * @param context any {@link Context}. * @see #transform(Class, Transformation) * @see #optionalCenterCrop() * * @deprecated Use {@link #centerCrop()}. */ @Deprecated public RequestOptions centerCrop(@SuppressWarnings("unused") Context context) { return centerCrop(); } /** * Applies {@link CenterCrop} to all default types and * throws an exception if asked to transform an unknown type. * * <p>this will override previous calls to {@link #dontTransform()} ()}. * * @see #transform(Class, Transformation) * @see #optionalCenterCrop() */ public RequestOptions centerCrop() { return transform(DownsampleStrategy.CENTER_OUTSIDE, new CenterCrop()); } /** * Applies {@link com.bumptech.glide.load.resource.bitmap.FitCenter} to all default types, and * ignores unknown types. * * <p>This will override previous calls to {@link #dontTransform()}. * * @see #optionalTransform(Class, Transformation) * @see #fitCenter() */ public RequestOptions optionalFitCenter() { return optionalTransform(DownsampleStrategy.FIT_CENTER, new FitCenter()); } /** * Applies {@link FitCenter} to all default types and * throws an exception if asked to transform an unknown type. * * <p>This will override previous calls to {@link #dontTransform()}. * * @see #transform(Class, Transformation) * @see #optionalFitCenter() */ public RequestOptions fitCenter() { return transform(DownsampleStrategy.FIT_CENTER, new FitCenter()); } /** * Applies {@link com.bumptech.glide.load.resource.bitmap.CenterInside} to all default types, and * ignores unknown types. * * <p>This will override previous calls to {@link #dontTransform()}. * * @param context Any {@link Context}. * @see #optionalTransform(Class, Transformation) * @see #centerInside() * * @deprecated Use {@link #optionalCenterInside()} */ @Deprecated public RequestOptions optionalCenterInside(@SuppressWarnings("unused") Context context) { return optionalCenterInside(); } /** * Applies {@link com.bumptech.glide.load.resource.bitmap.CenterInside} to all default types, and * ignores unknown types. * * <p>This will override previous calls to {@link #dontTransform()}. * * @see #optionalTransform(Class, Transformation) * @see #centerInside() */ public RequestOptions optionalCenterInside() { return optionalTransform(DownsampleStrategy.CENTER_INSIDE, new CenterInside()); } /** * Applies {@link CenterInside} to all default types and * throws an exception if asked to transform an unknown type. * * <p>This will override previous calls to {@link #dontTransform()}. * * @see #transform(Class, Transformation) * @see #optionalCenterInside() */ public RequestOptions centerInside() { return transform(DownsampleStrategy.CENTER_INSIDE, new CenterInside()); } /** * Applies {@link CircleCrop} to all default types, and ignores unknown types. * * <p>This will override previous calls to {@link #dontTransform()}. * * @see #optionalTransform(Transformation) * @see #circleCrop() */ public RequestOptions optionalCircleCrop() { return optionalTransform(DownsampleStrategy.CENTER_OUTSIDE, new CircleCrop()); } /** * Applies {@link CircleCrop} to all default types and throws an exception if asked to transform * an unknown type. * * <p>This will override previous calls to {@link #dontTransform()}. * * @param context Any {@link Context}. * @see #transform(Class, Transformation) * @see #optionalCenterCrop() * * @deprecated Use {@link #circleCrop()}. */ @Deprecated public RequestOptions circleCrop(@SuppressWarnings("unused") Context context) { return circleCrop(); } /** * Applies {@link CircleCrop} to all default types and throws an exception if asked to transform * an unknown type. * * <p>This will override previous calls to {@link #dontTransform()}. * * @see #transform(Class, Transformation) * @see #optionalCenterCrop() */ public RequestOptions circleCrop() { return transform(DownsampleStrategy.CENTER_INSIDE, new CircleCrop()); } // calling optionalTransform() on the result of clone() requires greater access. @SuppressWarnings("WeakerAccess") final RequestOptions optionalTransform(DownsampleStrategy downsampleStrategy, Transformation<Bitmap> transformation) { if (isAutoCloneEnabled) { return clone().optionalTransform(downsampleStrategy, transformation); } downsample(downsampleStrategy); return optionalTransform(transformation); } // calling transform() on the result of clone() requires greater access. @SuppressWarnings("WeakerAccess") final RequestOptions transform(DownsampleStrategy downsampleStrategy, Transformation<Bitmap> transformation) { if (isAutoCloneEnabled) { return clone().transform(downsampleStrategy, transformation); } downsample(downsampleStrategy); return transform(transformation); } /** * Applies the given {@link Transformation} for * {@link Bitmap Bitmaps} to the default types ({@link Bitmap}, * {@link android.graphics.drawable.BitmapDrawable}, and * {@link com.bumptech.glide.load.resource.gif.GifDrawable}) * and throws an exception if asked to transform an unknown type. * * <p>This will override previous calls to {@link #dontTransform()}. * * @param transformation Any {@link Transformation} for * {@link Bitmap}s. * @see #optionalTransform(Transformation) * @see #optionalTransform(Class, Transformation) */ public RequestOptions transform(@NonNull Transformation<Bitmap> transformation) { if (isAutoCloneEnabled) { return clone().transform(transformation); } optionalTransform(transformation); isTransformationRequired = true; fields |= TRANSFORMATION_REQUIRED; return selfOrThrowIfLocked(); } /** * Applies the given {@link Transformation} for * {@link Bitmap Bitmaps} to the default types ({@link Bitmap}, * {@link android.graphics.drawable.BitmapDrawable}, and * {@link com.bumptech.glide.load.resource.gif.GifDrawable}) and ignores unknown types. * * <p>This will override previous calls to {@link #dontTransform()}. * * @param context Any {@link Context}. * @param transformation Any {@link Transformation} for * {@link Bitmap}s. * @see #transform(Class, Transformation) * * @deprecated Use {@link #optionalTransform(Transformation)} */ @Deprecated public RequestOptions optionalTransform(Context context, Transformation<Bitmap> transformation) { return optionalTransform(transformation); } /** * Applies the given {@link Transformation} for * {@link Bitmap Bitmaps} to the default types ({@link Bitmap}, * {@link android.graphics.drawable.BitmapDrawable}, and * {@link com.bumptech.glide.load.resource.gif.GifDrawable}) and ignores unknown types. * * <p>This will override previous calls to {@link #dontTransform()}. * * @param transformation Any {@link Transformation} for * {@link Bitmap}s. * @see #transform(Transformation) * @see #transform(Class, Transformation) */ public RequestOptions optionalTransform(Transformation<Bitmap> transformation) { if (isAutoCloneEnabled) { return clone().optionalTransform(transformation); } optionalTransform(Bitmap.class, transformation); // TODO: remove BitmapDrawable decoder and this transformation. optionalTransform(BitmapDrawable.class, new BitmapDrawableTransformation(transformation)); optionalTransform(GifDrawable.class, new GifDrawableTransformation(transformation)); return selfOrThrowIfLocked(); } /** * Applies the given {@link Transformation} for any decoded resource of * the given type and allows unknown resource types to be ignored. * * <p> Users can apply different transformations for each resource class. Applying a * {@link Transformation} for a resource type that already has a * {@link Transformation} will override the previous call. </p> * * <p> If any calls are made to the non-optional transform methods, then attempting to transform * an unknown resource class will throw an exception. To allow unknown types, users must always * call the optional version of each method. </p> * * <p>This will override previous calls to {@link #dontTransform()}. * * @param resourceClass The type of resource to transform. * @param transformation The {@link Transformation} to apply. */ public <T> RequestOptions optionalTransform(Class<T> resourceClass, Transformation<T> transformation) { if (isAutoCloneEnabled) { return clone().optionalTransform(resourceClass, transformation); } Preconditions.checkNotNull(resourceClass); Preconditions.checkNotNull(transformation); transformations.put(resourceClass, transformation); fields |= TRANSFORMATION; isTransformationAllowed = true; fields |= TRANSFORMATION_ALLOWED; return selfOrThrowIfLocked(); } /** * Applies the given {@link Transformation} for any decoded resource of * the given type and throws if asked to transform an unknown resource type. * * <p>This will override previous calls to {@link #dontTransform()}. * * @param resourceClass The type of resource to transform. * @param transformation The {@link Transformation} to apply. * @see #optionalTransform(Class, Transformation) */ public <T> RequestOptions transform( Class<T> resourceClass, Transformation<T> transformation) { if (isAutoCloneEnabled) { return clone().transform(resourceClass, transformation); } optionalTransform(resourceClass, transformation); isTransformationRequired = true; fields |= TRANSFORMATION_REQUIRED; return selfOrThrowIfLocked(); } /** * Removes all applied {@link Transformation Transformations} for all * resource classes and allows unknown resource types to be transformed without throwing an * exception. */ public RequestOptions dontTransform() { if (isAutoCloneEnabled) { return clone().dontTransform(); } transformations.clear(); fields &= ~TRANSFORMATION; isTransformationRequired = false; fields &= ~TRANSFORMATION_REQUIRED; isTransformationAllowed = false; fields |= TRANSFORMATION_ALLOWED; return selfOrThrowIfLocked(); } /** * Disables resource decoders that return animated resources so any resource returned will be * static. * * <p> To disable transitions (fades etc) use * {@link com.bumptech.glide.TransitionOptions#dontTransition()}</p> */ public RequestOptions dontAnimate() { if (isAutoCloneEnabled) { return clone().dontAnimate(); } set(ByteBufferGifDecoder.DISABLE_ANIMATION, true); set(StreamGifDecoder.DISABLE_ANIMATION, true); return selfOrThrowIfLocked(); } public RequestOptions apply(RequestOptions other) { if (isAutoCloneEnabled) { return clone().apply(other); } if (isSet(other.fields, SIZE_MULTIPLIER)) { sizeMultiplier = other.sizeMultiplier; } if (isSet(other.fields, USE_UNLIMITED_SOURCE_GENERATORS_POOL)) { useUnlimitedSourceGeneratorsPool = other.useUnlimitedSourceGeneratorsPool; } if (isSet(other.fields, DISK_CACHE_STRATEGY)) { diskCacheStrategy = other.diskCacheStrategy; } if (isSet(other.fields, PRIORITY)) { priority = other.priority; } if (isSet(other.fields, ERROR_PLACEHOLDER)) { errorPlaceholder = other.errorPlaceholder; } if (isSet(other.fields, ERROR_ID)) { errorId = other.errorId; } if (isSet(other.fields, PLACEHOLDER)) { placeholderDrawable = other.placeholderDrawable; } if (isSet(other.fields, PLACEHOLDER_ID)) { placeholderId = other.placeholderId; } if (isSet(other.fields, IS_CACHEABLE)) { isCacheable = other.isCacheable; } if (isSet(other.fields, OVERRIDE)) { overrideWidth = other.overrideWidth; overrideHeight = other.overrideHeight; } if (isSet(other.fields, SIGNATURE)) { signature = other.signature; } if (isSet(other.fields, RESOURCE_CLASS)) { resourceClass = other.resourceClass; } if (isSet(other.fields, FALLBACK)) { fallbackDrawable = other.fallbackDrawable; } if (isSet(other.fields, FALLBACK_ID)) { fallbackId = other.fallbackId; } if (isSet(other.fields, THEME)) { theme = other.theme; } if (isSet(other.fields, TRANSFORMATION_ALLOWED)) { isTransformationAllowed = other.isTransformationAllowed; } if (isSet(other.fields, TRANSFORMATION_REQUIRED)) { isTransformationRequired = other.isTransformationRequired; } if (isSet(other.fields, TRANSFORMATION)) { transformations.putAll(other.transformations); } if (isSet(other.fields, ONLY_RETRIEVE_FROM_CACHE)) { onlyRetrieveFromCache = other.onlyRetrieveFromCache; } // Applying options with dontTransform() is expected to clear our transformations. if (!isTransformationAllowed) { transformations.clear(); fields &= ~TRANSFORMATION; isTransformationRequired = false; fields &= ~TRANSFORMATION_REQUIRED; } fields |= other.fields; options.putAll(other.options); return selfOrThrowIfLocked(); } /** * Throws if any further mutations are attempted. * * <p> Once locked, the only way to unlock is to use {@link #clone()} </p> */ @SuppressWarnings("unchecked") public RequestOptions lock() { isLocked = true; // This is the only place we should not check locked. return (RequestOptions) this; } /** * Similar to {@link #lock()} except that mutations cause a {@link #clone()} operation to happen * before the mutation resulting in all methods returning a new Object and leaving the original * locked object unmodified. * * <p>Auto clone is not retained by cloned objects returned from mutations. The cloned objects * are mutable and are not locked. */ public RequestOptions autoClone() { if (isLocked && !isAutoCloneEnabled) { throw new IllegalStateException("You cannot auto lock an already locked options object" + ", try clone() first"); } isAutoCloneEnabled = true; return lock(); } @SuppressWarnings("unchecked") private RequestOptions selfOrThrowIfLocked() { if (isLocked) { throw new IllegalStateException("You cannot modify locked RequestOptions, consider clone()"); } return (RequestOptions) this; } public final Map<Class<?>, Transformation<?>> getTransformations() { return transformations; } public final boolean isTransformationRequired() { return isTransformationRequired; } public final Options getOptions() { return options; } public final Class<?> getResourceClass() { return resourceClass; } public final DiskCacheStrategy getDiskCacheStrategy() { return diskCacheStrategy; } public final Drawable getErrorPlaceholder() { return errorPlaceholder; } public final int getErrorId() { return errorId; } public final int getPlaceholderId() { return placeholderId; } public final Drawable getPlaceholderDrawable() { return placeholderDrawable; } public final int getFallbackId() { return fallbackId; } public final Drawable getFallbackDrawable() { return fallbackDrawable; } public final Resources.Theme getTheme() { return theme; } public final boolean isMemoryCacheable() { return isCacheable; } public final Key getSignature() { return signature; } public final boolean isPrioritySet() { return isSet(PRIORITY); } public final Priority getPriority() { return priority; } public final int getOverrideWidth() { return overrideWidth; } public final boolean isValidOverride() { return Util.isValidDimensions(overrideWidth, overrideHeight); } public final int getOverrideHeight() { return overrideHeight; } public final float getSizeMultiplier() { return sizeMultiplier; } private boolean isSet(int flag) { return isSet(fields, flag); } public final boolean getUseUnlimitedSourceGeneratorsPool() { return useUnlimitedSourceGeneratorsPool; } public final boolean getOnlyRetrieveFromCache() { return onlyRetrieveFromCache; } }