package com.bumptech.glide.load; import android.support.annotation.Nullable; import com.bumptech.glide.util.Preconditions; import java.security.MessageDigest; /** * Defines available component (decoders, encoders, model loaders etc.) options with optional * default values and the ability to affect the resource disk cache key used by {@link * com.bumptech.glide.load.engine.DiskCacheStrategy#RESOURCE}. * * <p> * Implementations must either be unique (usually declared as static final variables), or * implement {@link #equals(Object)} and {@link #hashCode()}. * </p> * * <p> * Implementations can implement {@link #update(Object, MessageDigest)} to make sure that * the disk cache key includes the specific option set. * </p> * * @param <T> The type of the option ({@link Integer}, {@link * android.graphics.Bitmap.CompressFormat} etc.), must implement {@link #equals(Object)} and * {@link #hashCode()}. */ public final class Option<T> { private static final CacheKeyUpdater<Object> EMPTY_UPDATER = new CacheKeyUpdater<Object>() { @Override public void update(byte[] keyBytes, Object value, MessageDigest messageDigest) { // Do nothing. } }; private final T defaultValue; private final CacheKeyUpdater<T> cacheKeyUpdater; private final String key; private volatile byte[] keyBytes; /** * Returns a new {@link Option} that does not affect disk cache keys with a {@code null} default * value. * * @param key A unique package prefixed {@link String} that identifies this option (must be * stable across builds, so {@link Class#getName()} should <em>not</em> be used). */ public static <T> Option<T> memory(String key) { return new Option<>(key, null /*defaultValue*/, Option.<T>emptyUpdater()); } /** * Returns a new {@link Option} that does not affect disk cache keys with the given value as the * default value. * * @param key A unique package prefixed {@link String} that identifies this option (must be * stable across builds, so {@link Class#getName()} should <em>not</em> be used). */ public static <T> Option<T> memory(String key, T defaultValue) { return new Option<>(key, defaultValue, Option.<T>emptyUpdater()); } /** * Returns a new {@link Option} that uses the given {@link * com.bumptech.glide.load.Option.CacheKeyUpdater} to update disk cache keys. * * @param key A unique package prefixed {@link String} that identifies this option (must be * stable across builds, so {@link Class#getName()} should <em>not</em> be used). */ public static <T> Option<T> disk(String key, CacheKeyUpdater<T> cacheKeyUpdater) { return new Option<>(key, null /*defaultValue*/, cacheKeyUpdater); } /** * Returns a new {@link Option} that uses the given {@link * com.bumptech.glide.load.Option.CacheKeyUpdater} to update disk cache keys and provides * the given value as the default value. * * @param key A unique package prefixed {@link String} that identifies this option (must be * stable across builds, so {@link Class#getName()} should <em>not</em> be used). */ public static <T> Option<T> disk(String key, T defaultValue, CacheKeyUpdater<T> cacheKeyUpdater) { return new Option<>(key, defaultValue, cacheKeyUpdater); } Option(String key, T defaultValue, CacheKeyUpdater<T> cacheKeyUpdater) { this.key = Preconditions.checkNotEmpty(key); this.defaultValue = defaultValue; this.cacheKeyUpdater = Preconditions.checkNotNull(cacheKeyUpdater); } /** * Returns a reasonable default to use if no other value is set, or {@code null}. */ @Nullable public T getDefaultValue() { return defaultValue; } /** * Updates the given {@link MessageDigest} used to construct a cache key with the given * value using the {@link com.bumptech.glide.load.Option.CacheKeyUpdater} optionally provided in * the constructor. */ public void update(T value, MessageDigest messageDigest) { cacheKeyUpdater.update(getKeyBytes(), value, messageDigest); } private byte[] getKeyBytes() { if (keyBytes == null) { keyBytes = key.getBytes(Key.CHARSET); } return keyBytes; } @Override public boolean equals(Object o) { if (o instanceof Option) { Option<?> other = (Option<?>) o; return key.equals(other.key); } return false; } @Override public int hashCode() { return key.hashCode(); } @SuppressWarnings("unchecked") private static <T> CacheKeyUpdater<T> emptyUpdater() { return (CacheKeyUpdater<T>) EMPTY_UPDATER; } @Override public String toString() { return "Option{" + "key='" + key + '\'' + '}'; } /** * An interface that updates a {@link MessageDigest} with the given value as part of a process to * generate a disk cache key. * * @param <T> The type of the option. */ public interface CacheKeyUpdater<T> { /** * Updates the given {@link MessageDigest} with the bytes of the given key (to avoid incidental * value collisions when values are not particularly unique) and value. */ void update(byte[] keyBytes, T value, MessageDigest messageDigest); } }