From 562f73a8c9a51406b8fbc1b6b1bc0d24609855b2 Mon Sep 17 00:00:00 2001 From: billdawson Date: Fri, 26 Sep 2014 23:54:56 +0200 Subject: [PATCH 1/8] NetworkRequestHandler recognizes GIFs ... ... and when finding one will make the stream available for any special non-picasso gif handling to use later on. (Picasso does not support animated GIFs). In this case, the Bitmap will not be created. --- .../picasso/NetworkRequestHandler.java | 88 +++++++++++++++--- .../com/squareup/picasso/RequestHandler.java | 84 +++++++++++------ .../main/java/com/squareup/picasso/Utils.java | 90 +++++++++++-------- 3 files changed, 189 insertions(+), 73 deletions(-) diff --git a/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java b/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java index 484a17f..442b009 100644 --- a/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java @@ -15,15 +15,17 @@ */ package com.squareup.picasso; +import static com.squareup.picasso.Picasso.LoadedFrom.DISK; +import static com.squareup.picasso.Picasso.LoadedFrom.NETWORK; + +import java.io.IOException; +import java.io.InputStream; + import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.NetworkInfo; -import java.io.IOException; -import java.io.InputStream; -import static com.squareup.picasso.Downloader.Response; -import static com.squareup.picasso.Picasso.LoadedFrom.DISK; -import static com.squareup.picasso.Picasso.LoadedFrom.NETWORK; +import com.squareup.picasso.Downloader.Response; class NetworkRequestHandler extends RequestHandler { static final int RETRY_COUNT = 2; @@ -35,6 +37,18 @@ class NetworkRequestHandler extends RequestHandler { private final Downloader downloader; private final Stats stats; + static class DecodeResult { + /** + * If null, check isGif and inputStream. + */ + Bitmap bitmap; + /** + * Null if bitmap is non-null. Used only for a GIF stream. + */ + InputStream inputStream; + boolean isGif; + } + public NetworkRequestHandler(Downloader downloader, Stats stats) { this.downloader = downloader; this.stats = stats; @@ -62,7 +76,8 @@ public NetworkRequestHandler(Downloader downloader, Stats stats) { if (is == null) { return null; } - // Sometimes response content length is zero when requests are being replayed. Haven't found + // Sometimes response content length is zero when requests are being + // replayed. Haven't found // root cause to this but retrying the request seems safe to do so. if (response.getContentLength() == 0) { Utils.closeQuietly(is); @@ -71,10 +86,19 @@ public NetworkRequestHandler(Downloader downloader, Stats stats) { if (loadedFrom == NETWORK && response.getContentLength() > 0) { stats.dispatchDownloadFinished(response.getContentLength()); } + + boolean isGif = false; try { - return new Result(decodeStream(is, data), loadedFrom); + DecodeResult result = decodeWithGifRecognition(is, data); + isGif = result.isGif; + if (isGif) { + return new Result(result.inputStream, loadedFrom); + } + return new Result(result.bitmap, loadedFrom); } finally { - Utils.closeQuietly(is); + if (!isGif) { + Utils.closeQuietly(is); + } } } @@ -90,9 +114,50 @@ public NetworkRequestHandler(Downloader downloader, Stats stats) { return true; } + /** + * Will check first if stream is GIF. If so, will put the stream in the result and + * return immediately. If not, calls {@link #decodeStream(InputStream, Request)} and + * puts resulting bitmap in result. + * + * @param stream + * @param data + * @return {@link DecodeResult} + * @throws IOException + */ + private DecodeResult decodeWithGifRecognition(InputStream stream, Request data) + throws IOException { + MarkableInputStream markStream; + if (stream instanceof MarkableInputStream) { + markStream = (MarkableInputStream) stream; + } else { + markStream = new MarkableInputStream(stream); + } + + long mark = markStream.savePosition(MARKER); + DecodeResult result = new DecodeResult(); + result.isGif = Utils.isGifFile(markStream); + markStream.reset(mark); + + if (result.isGif) { + result.bitmap = null; + result.inputStream = markStream; + } else { + result.bitmap = decodeStream(markStream, data); + result.inputStream = null; + } + + return result; + } + private Bitmap decodeStream(InputStream stream, Request data) throws IOException { - MarkableInputStream markStream = new MarkableInputStream(stream); - stream = markStream; + MarkableInputStream markStream; + + if (stream instanceof MarkableInputStream) { + markStream = (MarkableInputStream) stream; + } else { + markStream = new MarkableInputStream(stream); + stream = markStream; + } long mark = markStream.savePosition(MARKER); @@ -101,7 +166,8 @@ private Bitmap decodeStream(InputStream stream, Request data) throws IOException boolean isWebPFile = Utils.isWebPFile(stream); markStream.reset(mark); - // When decode WebP network stream, BitmapFactory throw JNI Exception and make app crash. + // When decode WebP network stream, BitmapFactory throw JNI Exception and + // make app crash. // Decode byte array instead if (isWebPFile) { byte[] bytes = Utils.toByteArray(stream); diff --git a/picasso/src/main/java/com/squareup/picasso/RequestHandler.java b/picasso/src/main/java/com/squareup/picasso/RequestHandler.java index e1108fe..32a206b 100644 --- a/picasso/src/main/java/com/squareup/picasso/RequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/RequestHandler.java @@ -15,34 +15,41 @@ */ package com.squareup.picasso; +import java.io.IOException; +import java.io.InputStream; + import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.NetworkInfo; -import java.io.IOException; +import com.squareup.picasso.Picasso.LoadedFrom; /** - * {@link RequestHandler} allows you to extend Picasso to load images - * in ways that are not supported by default in the library. + * {@link RequestHandler} allows you to extend Picasso to load images in ways + * that are not supported by default in the library. *

*

Usage

- *

{@link RequestHandler} must be subclassed to be used. You will have to + *

+ * {@link RequestHandler} must be subclassed to be used. You will have to * override two methods ({@link #canHandleRequest(Request)} and - * {@link #load(Request)}) with your custom logic to load images.

- * - *

You should then register your {@link RequestHandler} using - * {@link Picasso.Builder#addRequestHandler(RequestHandler)}

- * - * NOTE: This is a beta feature. The API is subject to change in a backwards - * incompatible way at any time. - * + * {@link #load(Request)}) with your custom logic to load images. + *

+ * + *

+ * You should then register your {@link RequestHandler} using + * {@link Picasso.Builder#addRequestHandler(RequestHandler)} + *

+ * + * NOTE: This is a beta feature. The API is subject to change in a + * backwards incompatible way at any time. + * * @see Picasso.Builder#addRequestHandler(RequestHandler) */ public abstract class RequestHandler { /** * {@link Result} represents the result of a {@link #load(Request)} call in a * {@link RequestHandler}. - * + * * @see RequestHandler * @see #load(Request) */ @@ -50,37 +57,63 @@ public static final class Result { private final Picasso.LoadedFrom loadedFrom; private final Bitmap bitmap; private final int exifOrientation; + private final InputStream gifStream; // For GIFs only public Result(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) { this(bitmap, loadedFrom, 0); } + /** + * Use only when stream has been identified as containing GIF data. + * + * @param gifStream {@link InputStream} containing GIF data. + * @param loadedFrom {@link LoadedFrom}. + */ + public Result(InputStream gifStream, Picasso.LoadedFrom loadedFrom) { + this.gifStream = gifStream; + this.bitmap = null; + this.loadedFrom = loadedFrom; + this.exifOrientation = 0; + } + Result(Bitmap bitmap, Picasso.LoadedFrom loadedFrom, int exifOrientation) { this.bitmap = bitmap; + this.gifStream = null; this.loadedFrom = loadedFrom; this.exifOrientation = exifOrientation; } /** - * Returns the resulting {@link Bitmap} generated - * from a {@link #load(Request)} call. + * Returns the resulting {@link Bitmap} generated from a + * {@link #load(Request)} call. */ public Bitmap getBitmap() { return bitmap; } /** - * Returns the resulting {@link Picasso.LoadedFrom} generated - * from a {@link #load(Request)} call. + * Returns the resulting {@link Picasso.LoadedFrom} generated from a + * {@link #load(Request)} call. */ public Picasso.LoadedFrom getLoadedFrom() { return loadedFrom; } /** - * Returns the resulting EXIF orientation generated - * from a {@link #load(Request)} call. This is only accessible - * to built-in RequestHandlers. + * Returns an {@link InputStream} containing GIF data. If this is non-null, + * it is an indication that the resource was identified as a GIF and + * not decoded into a {@link Bitmap}, thus {@link #getBitmap()} will + * return null. This stream can then be used by a separate GIF + * decoding library, since Picasso does not support animated GIFs. + */ + public InputStream getGifStream() { + return gifStream; + } + + /** + * Returns the resulting EXIF orientation generated from a + * {@link #load(Request)} call. This is only accessible to built-in + * RequestHandlers. */ int getExifOrientation() { return exifOrientation; @@ -95,7 +128,7 @@ int getExifOrientation() { /** * Loads an image for the given {@link Request}. - * + * * @param data the {@link android.net.Uri} to load the image from. * @return A {@link Result} instance representing the result. */ @@ -114,8 +147,8 @@ boolean supportsReplay() { } /** - * Lazily create {@link BitmapFactory.Options} based in given - * {@link Request}, only instantiating them if needed. + * Lazily create {@link BitmapFactory.Options} based in given {@link Request}, + * only instantiating them if needed. */ static BitmapFactory.Options createBitmapOptions(Request data) { final boolean justBounds = data.hasSize(); @@ -147,9 +180,8 @@ static void calculateInSampleSize(int reqWidth, int reqHeight, int width, int he if (height > reqHeight || width > reqWidth) { final int heightRatio = (int) Math.floor((float) height / (float) reqHeight); final int widthRatio = (int) Math.floor((float) width / (float) reqWidth); - sampleSize = request.centerInside - ? Math.max(heightRatio, widthRatio) - : Math.min(heightRatio, widthRatio); + sampleSize = request.centerInside ? Math.max(heightRatio, widthRatio) : Math.min(heightRatio, + widthRatio); } options.inSampleSize = sampleSize; options.inJustDecodeBounds = false; diff --git a/picasso/src/main/java/com/squareup/picasso/Utils.java b/picasso/src/main/java/com/squareup/picasso/Utils.java index 70aa8fd..cb66fbb 100644 --- a/picasso/src/main/java/com/squareup/picasso/Utils.java +++ b/picasso/src/main/java/com/squareup/picasso/Utils.java @@ -15,6 +15,24 @@ */ package com.squareup.picasso; +import static android.content.Context.ACTIVITY_SERVICE; +import static android.content.pm.ApplicationInfo.FLAG_LARGE_HEAP; +import static android.os.Build.VERSION.SDK_INT; +import static android.os.Build.VERSION_CODES.HONEYCOMB; +import static android.os.Build.VERSION_CODES.HONEYCOMB_MR1; +import static android.os.Process.THREAD_PRIORITY_BACKGROUND; +import static android.provider.Settings.System.AIRPLANE_MODE_ON; +import static com.squareup.picasso.Picasso.TAG; +import static java.lang.String.format; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.concurrent.ThreadFactory; + import android.annotation.TargetApi; import android.app.ActivityManager; import android.content.ContentResolver; @@ -27,25 +45,9 @@ import android.os.StatFs; import android.provider.Settings; import android.util.Log; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.concurrent.ThreadFactory; - -import static android.content.Context.ACTIVITY_SERVICE; -import static android.content.pm.ApplicationInfo.FLAG_LARGE_HEAP; -import static android.os.Build.VERSION.SDK_INT; -import static android.os.Build.VERSION_CODES.HONEYCOMB; -import static android.os.Build.VERSION_CODES.HONEYCOMB_MR1; -import static android.os.Process.THREAD_PRIORITY_BACKGROUND; -import static android.provider.Settings.System.AIRPLANE_MODE_ON; -import static com.squareup.picasso.Picasso.TAG; -import static java.lang.String.format; final class Utils { + static final String THREAD_PREFIX = "Picasso-"; static final String THREAD_IDLE_NAME = THREAD_PREFIX + "Idle"; static final int DEFAULT_READ_TIMEOUT = 20 * 1000; // 20s @@ -81,6 +83,7 @@ final class Utils { static final String VERB_PAUSED = "paused"; static final String VERB_RESUMED = "resumed"; + // @formatter:off /* WebP file header 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -92,10 +95,14 @@ final class Utils { | 'W' | 'E' | 'B' | 'P' | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ + // @formatter:on private static final int WEBP_FILE_HEADER_SIZE = 12; private static final String WEBP_FILE_HEADER_RIFF = "RIFF"; private static final String WEBP_FILE_HEADER_WEBP = "WEBP"; + private static final int GIF_FILE_HEADER_SIZE = 4; + private static final String GIF_FILE_HEADER = "GIF8"; + private Utils() { // No instances. } @@ -142,7 +149,8 @@ static String getLogIdsForHunter(BitmapHunter hunter, String prefix) { List actions = hunter.getActions(); if (actions != null) { for (int i = 0, count = actions.size(); i < count; i++) { - if (i > 0 || action != null) builder.append(", "); + if (i > 0 || action != null) + builder.append(", "); builder.append(actions.get(i).request.logId()); } } @@ -192,7 +200,7 @@ static String createKey(Request data, StringBuilder builder) { } if (data.transformations != null) { - //noinspection ForLoopReplaceableByForEach + // noinspection ForLoopReplaceableByForEach for (int i = 0, count = data.transformations.size(); i < count; i++) { builder.append(data.transformations.get(i).key()); builder.append('\n'); @@ -203,14 +211,18 @@ static String createKey(Request data, StringBuilder builder) { } static void closeQuietly(InputStream is) { - if (is == null) return; + if (is == null) + return; try { is.close(); } catch (IOException ignored) { } } - /** Returns {@code true} if header indicates the response body was loaded from the disk cache. */ + /** + * Returns {@code true} if header indicates the response body was loaded from the disk + * cache. + */ static boolean parseResponseSourceHeader(String header) { if (header == null) { return false; @@ -245,23 +257,21 @@ static Downloader createDefaultDownloader(Context context) { } if (okHttpClient != okUrlFactory) { - throw new RuntimeException("" - + "Picasso detected an unsupported OkHttp on the classpath.\n" + throw new RuntimeException("" + "Picasso detected an unsupported OkHttp on the classpath.\n" + "To use OkHttp with this version of Picasso, you'll need:\n" + "1. com.squareup.okhttp:okhttp:1.6.0 (or newer)\n" + "2. com.squareup.okhttp:okhttp-urlconnection:1.6.0 (or newer)\n" + "Note that OkHttp 2.0.0+ is supported!"); } - return okHttpClient - ? OkHttpLoaderCreator.create(context) + return okHttpClient ? OkHttpLoaderCreator.create(context) : new UrlConnectionDownloader(context); } static File createDefaultCacheDir(Context context) { File cache = new File(context.getApplicationContext().getCacheDir(), PICASSO_CACHE); if (!cache.exists()) { - //noinspection ResultOfMethodCallIgnored + // noinspection ResultOfMethodCallIgnored cache.mkdirs(); } return cache; @@ -298,8 +308,7 @@ static boolean isAirplaneModeOn(Context context) { return Settings.System.getInt(contentResolver, AIRPLANE_MODE_ON, 0) != 0; } - @SuppressWarnings("unchecked") - static T getService(Context context, String service) { + @SuppressWarnings("unchecked") static T getService(Context context, String service) { return (T) context.getSystemService(service); } @@ -317,6 +326,16 @@ static byte[] toByteArray(InputStream input) throws IOException { return byteArrayOutputStream.toByteArray(); } + static boolean isGifFile(InputStream stream) throws IOException { + byte[] fileHeaderBytes = new byte[GIF_FILE_HEADER_SIZE]; + boolean isGifFile = false; + if (stream.read(fileHeaderBytes, 0, GIF_FILE_HEADER_SIZE) == GIF_FILE_HEADER_SIZE) { + isGifFile = GIF_FILE_HEADER.equals(new String(fileHeaderBytes, 0, 4, "US-ASCII")); + } + + return isGifFile; + } + static boolean isWebPFile(InputStream stream) throws IOException { byte[] fileHeaderBytes = new byte[WEBP_FILE_HEADER_SIZE]; boolean isWebPFile = false; @@ -334,7 +353,8 @@ static int getResourceId(Resources resources, Request data) throws FileNotFoundE } String pkg = data.uri.getAuthority(); - if (pkg == null) throw new FileNotFoundException("No package provided: " + data.uri); + if (pkg == null) + throw new FileNotFoundException("No package provided: " + data.uri); int id; List segments = data.uri.getPathSegments(); @@ -363,7 +383,8 @@ static Resources getResources(Context context, Request data) throws FileNotFound } String pkg = data.uri.getAuthority(); - if (pkg == null) throw new FileNotFoundException("No package provided: " + data.uri); + if (pkg == null) + throw new FileNotFoundException("No package provided: " + data.uri); try { PackageManager pm = context.getPackageManager(); return pm.getResourcesForApplication(pkg); @@ -372,16 +393,14 @@ static Resources getResources(Context context, Request data) throws FileNotFound } } - @TargetApi(HONEYCOMB) - private static class ActivityManagerHoneycomb { + @TargetApi(HONEYCOMB) private static class ActivityManagerHoneycomb { static int getLargeMemoryClass(ActivityManager activityManager) { return activityManager.getLargeMemoryClass(); } } static class PicassoThreadFactory implements ThreadFactory { - @SuppressWarnings("NullableProblems") - public Thread newThread(Runnable r) { + @Override @SuppressWarnings("NullableProblems") public Thread newThread(Runnable r) { return new PicassoThread(r); } } @@ -397,8 +416,7 @@ public PicassoThread(Runnable r) { } } - @TargetApi(HONEYCOMB_MR1) - private static class BitmapHoneycombMR1 { + @TargetApi(HONEYCOMB_MR1) private static class BitmapHoneycombMR1 { static int getByteCount(Bitmap bitmap) { return bitmap.getByteCount(); } From ba1a059be32ea28e1b6261e730a77352ef0b4841 Mon Sep 17 00:00:00 2001 From: billdawson Date: Mon, 29 Sep 2014 19:48:23 +0200 Subject: [PATCH 2/8] No longer return just bitmaps Instead, return an result object that can have either a bitmap or a stream identified as holding a GIF. --- .../java/com/squareup/picasso/Action.java | 5 +- .../com/squareup/picasso/BitmapHunter.java | 56 +++++++++++++------ .../java/com/squareup/picasso/Dispatcher.java | 7 ++- .../com/squareup/picasso/FetchAction.java | 4 +- .../java/com/squareup/picasso/GetAction.java | 4 +- .../com/squareup/picasso/ImageViewAction.java | 11 ++-- .../java/com/squareup/picasso/Picasso.java | 9 ++- .../squareup/picasso/RemoteViewsAction.java | 7 ++- .../com/squareup/picasso/RequestCreator.java | 12 ++-- .../java/com/squareup/picasso/Target.java | 11 +++- .../com/squareup/picasso/TargetAction.java | 25 ++++++--- .../squareup/picasso/BitmapHunterTest.java | 6 +- .../com/squareup/picasso/DispatcherTest.java | 2 +- .../squareup/picasso/ImageViewActionTest.java | 6 +- .../com/squareup/picasso/PicassoTest.java | 16 +++--- .../picasso/RemoteViewsActionTest.java | 4 +- .../squareup/picasso/RequestCreatorTest.java | 2 +- .../squareup/picasso/TargetActionTest.java | 13 ++++- .../java/com/squareup/picasso/TestUtils.java | 4 +- 19 files changed, 133 insertions(+), 71 deletions(-) diff --git a/picasso/src/main/java/com/squareup/picasso/Action.java b/picasso/src/main/java/com/squareup/picasso/Action.java index e6d305f..669fd21 100644 --- a/picasso/src/main/java/com/squareup/picasso/Action.java +++ b/picasso/src/main/java/com/squareup/picasso/Action.java @@ -15,8 +15,9 @@ */ package com.squareup.picasso; -import android.graphics.Bitmap; import android.graphics.drawable.Drawable; + +import com.squareup.picasso.BitmapHunter.ImageLoadResult; import com.squareup.picasso.Picasso.Priority; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; @@ -57,7 +58,7 @@ public RequestWeakReference(Action action, T referent, ReferenceQueue this.tag = (tag != null ? tag : this); } - abstract void complete(Bitmap result, Picasso.LoadedFrom from); + abstract void complete(ImageLoadResult result, Picasso.LoadedFrom from); abstract void error(); diff --git a/picasso/src/main/java/com/squareup/picasso/BitmapHunter.java b/picasso/src/main/java/com/squareup/picasso/BitmapHunter.java index 354ccda..1f24ed5 100644 --- a/picasso/src/main/java/com/squareup/picasso/BitmapHunter.java +++ b/picasso/src/main/java/com/squareup/picasso/BitmapHunter.java @@ -19,6 +19,7 @@ import android.graphics.Matrix; import android.net.NetworkInfo; import java.io.IOException; +import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; @@ -39,10 +40,25 @@ import static com.squareup.picasso.Utils.log; class BitmapHunter implements Runnable { + static class ImageLoadResult { + Bitmap bitmap; + InputStream gifStream; + + ImageLoadResult() { + this.bitmap = null; + this.gifStream = null; + } + + ImageLoadResult(Bitmap bitmap) { + this.bitmap = bitmap; + this.gifStream = null; + } + } + /** - * Global lock for bitmap decoding to ensure that we are only are decoding one at a time. Since - * this will only ever happen in background threads we help avoid excessive memory thrashing as - * well as potential OOMs. Shamelessly stolen from Volley. + * Global lock for bitmap decoding to ensure that we are only are decoding one at a + * time. Since this will only ever happen in background threads we help avoid excessive + * memory thrashing as well as potential OOMs. Shamelessly stolen from Volley. */ private static final Object DECODE_LOCK = new Object(); @@ -66,7 +82,7 @@ class BitmapHunter implements Runnable { Action action; List actions; - Bitmap result; + ImageLoadResult result; Future future; Picasso.LoadedFrom loadedFrom; Exception exception; @@ -124,56 +140,60 @@ class BitmapHunter implements Runnable { } } - Bitmap hunt() throws IOException { - Bitmap bitmap = null; + ImageLoadResult hunt() throws IOException { + ImageLoadResult huntResult = new ImageLoadResult(); if (!skipMemoryCache) { - bitmap = cache.get(key); - if (bitmap != null) { + huntResult.bitmap = cache.get(key); + if (huntResult.bitmap != null) { stats.dispatchCacheHit(); loadedFrom = MEMORY; if (picasso.loggingEnabled) { log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache"); } - return bitmap; + return huntResult; } } data.loadFromLocalCacheOnly = (retryCount == 0); RequestHandler.Result result = requestHandler.load(data); if (result != null) { - bitmap = result.getBitmap(); loadedFrom = result.getLoadedFrom(); exifRotation = result.getExifOrientation(); + huntResult.bitmap = result.getBitmap(); + huntResult.gifStream = result.getGifStream(); } - if (bitmap != null) { + if (huntResult.bitmap != null) { if (picasso.loggingEnabled) { log(OWNER_HUNTER, VERB_DECODED, data.logId()); } - stats.dispatchBitmapDecoded(bitmap); + stats.dispatchBitmapDecoded(huntResult.bitmap); if (data.needsTransformation() || exifRotation != 0) { synchronized (DECODE_LOCK) { if (data.needsMatrixTransform() || exifRotation != 0) { - bitmap = transformResult(data, bitmap, exifRotation); + huntResult.bitmap = transformResult(data, huntResult.bitmap, exifRotation); if (picasso.loggingEnabled) { log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId()); } } if (data.hasCustomTransformations()) { - bitmap = applyCustomTransformations(data.transformations, bitmap); + huntResult.bitmap = applyCustomTransformations(data.transformations, huntResult.bitmap); if (picasso.loggingEnabled) { log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from custom transformations"); } } } - if (bitmap != null) { - stats.dispatchBitmapTransformed(bitmap); + if (huntResult.bitmap != null) { + stats.dispatchBitmapTransformed(huntResult.bitmap); } } + } else if (huntResult.gifStream != null) { + // Pixate code to account for a GIF, which we handle + // separately. } - return bitmap; + return huntResult; } void attach(Action action) { @@ -282,7 +302,7 @@ boolean supportsReplay() { return requestHandler.supportsReplay(); } - Bitmap getResult() { + ImageLoadResult getResult() { return result; } diff --git a/picasso/src/main/java/com/squareup/picasso/Dispatcher.java b/picasso/src/main/java/com/squareup/picasso/Dispatcher.java index 7d02a52..9f8f3a3 100644 --- a/picasso/src/main/java/com/squareup/picasso/Dispatcher.java +++ b/picasso/src/main/java/com/squareup/picasso/Dispatcher.java @@ -36,6 +36,8 @@ import java.util.WeakHashMap; import java.util.concurrent.ExecutorService; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; + import static android.content.Context.CONNECTIVITY_SERVICE; import static android.content.Intent.ACTION_AIRPLANE_MODE_CHANGED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; @@ -345,8 +347,9 @@ void performRetry(BitmapHunter hunter) { } void performComplete(BitmapHunter hunter) { - if (!hunter.shouldSkipMemoryCache()) { - cache.set(hunter.getKey(), hunter.getResult()); + ImageLoadResult result = hunter.getResult(); + if (!hunter.shouldSkipMemoryCache() && result.bitmap != null) { + cache.set(hunter.getKey(), result.bitmap); } hunterMap.remove(hunter.getKey()); batch(hunter); diff --git a/picasso/src/main/java/com/squareup/picasso/FetchAction.java b/picasso/src/main/java/com/squareup/picasso/FetchAction.java index 490d5ec..4ddaebd 100644 --- a/picasso/src/main/java/com/squareup/picasso/FetchAction.java +++ b/picasso/src/main/java/com/squareup/picasso/FetchAction.java @@ -15,14 +15,14 @@ */ package com.squareup.picasso; -import android.graphics.Bitmap; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; class FetchAction extends Action { FetchAction(Picasso picasso, Request data, boolean skipCache, String key, Object tag) { super(picasso, null, data, skipCache, false, 0, null, key, tag); } - @Override void complete(Bitmap result, Picasso.LoadedFrom from) { + @Override void complete(ImageLoadResult result, Picasso.LoadedFrom from) { } @Override public void error() { diff --git a/picasso/src/main/java/com/squareup/picasso/GetAction.java b/picasso/src/main/java/com/squareup/picasso/GetAction.java index fadae7c..a928f29 100644 --- a/picasso/src/main/java/com/squareup/picasso/GetAction.java +++ b/picasso/src/main/java/com/squareup/picasso/GetAction.java @@ -15,14 +15,14 @@ */ package com.squareup.picasso; -import android.graphics.Bitmap; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; class GetAction extends Action { GetAction(Picasso picasso, Request data, boolean skipCache, String key, Object tag) { super(picasso, null, data, skipCache, false, 0, null, key, tag); } - @Override void complete(Bitmap result, Picasso.LoadedFrom from) { + @Override void complete(ImageLoadResult result, Picasso.LoadedFrom from) { } @Override public void error() { diff --git a/picasso/src/main/java/com/squareup/picasso/ImageViewAction.java b/picasso/src/main/java/com/squareup/picasso/ImageViewAction.java index a8fcee6..8ce7f77 100644 --- a/picasso/src/main/java/com/squareup/picasso/ImageViewAction.java +++ b/picasso/src/main/java/com/squareup/picasso/ImageViewAction.java @@ -16,10 +16,11 @@ package com.squareup.picasso; import android.content.Context; -import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.widget.ImageView; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; + class ImageViewAction extends Action { Callback callback; @@ -31,10 +32,10 @@ class ImageViewAction extends Action { this.callback = callback; } - @Override public void complete(Bitmap result, Picasso.LoadedFrom from) { + @Override public void complete(ImageLoadResult result, Picasso.LoadedFrom from) { if (result == null) { - throw new AssertionError( - String.format("Attempted to complete action with no result!\n%s", this)); + throw new AssertionError(String.format("Attempted to complete action with no result!\n%s", + this)); } ImageView target = this.target.get(); @@ -44,7 +45,7 @@ class ImageViewAction extends Action { Context context = picasso.context; boolean indicatorsEnabled = picasso.indicatorsEnabled; - PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled); + PicassoDrawable.setBitmap(target, context, result.bitmap, from, noFade, indicatorsEnabled); if (callback != null) { callback.onSuccess(); diff --git a/picasso/src/main/java/com/squareup/picasso/Picasso.java b/picasso/src/main/java/com/squareup/picasso/Picasso.java index b6758be..010f2a0 100644 --- a/picasso/src/main/java/com/squareup/picasso/Picasso.java +++ b/picasso/src/main/java/com/squareup/picasso/Picasso.java @@ -34,6 +34,8 @@ import java.util.WeakHashMap; import java.util.concurrent.ExecutorService; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; + import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static com.squareup.picasso.Action.RequestWeakReference; import static com.squareup.picasso.Dispatcher.HUNTER_BATCH_COMPLETE; @@ -449,7 +451,7 @@ void complete(BitmapHunter hunter) { Uri uri = hunter.getData().uri; Exception exception = hunter.getException(); - Bitmap result = hunter.getResult(); + ImageLoadResult result = hunter.getResult(); LoadedFrom from = hunter.getLoadedFrom(); if (single != null) { @@ -477,7 +479,8 @@ void resumeAction(Action action) { if (bitmap != null) { // Resumed action is cached, complete immediately. - deliverAction(bitmap, MEMORY, action); + ImageLoadResult result = new ImageLoadResult(bitmap); + deliverAction(result, MEMORY, action); if (loggingEnabled) { log(OWNER_MAIN, VERB_COMPLETED, action.request.logId(), "from " + MEMORY); } @@ -490,7 +493,7 @@ void resumeAction(Action action) { } } - private void deliverAction(Bitmap result, LoadedFrom from, Action action) { + private void deliverAction(ImageLoadResult result, LoadedFrom from, Action action) { if (action.isCancelled()) { return; } diff --git a/picasso/src/main/java/com/squareup/picasso/RemoteViewsAction.java b/picasso/src/main/java/com/squareup/picasso/RemoteViewsAction.java index 3607875..4f9a310 100644 --- a/picasso/src/main/java/com/squareup/picasso/RemoteViewsAction.java +++ b/picasso/src/main/java/com/squareup/picasso/RemoteViewsAction.java @@ -15,10 +15,11 @@ */ package com.squareup.picasso; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; + import android.app.Notification; import android.app.NotificationManager; import android.appwidget.AppWidgetManager; -import android.graphics.Bitmap; import android.widget.RemoteViews; import static android.content.Context.NOTIFICATION_SERVICE; @@ -36,8 +37,8 @@ abstract class RemoteViewsAction extends Action - * Note: The result of this operation is not cached in memory because the underlying - * {@link Cache} implementation is not guaranteed to be thread-safe. + * Note: The result of this operation is not cached in memory because the + * underlying {@link Cache} implementation is not guaranteed to be thread-safe. */ - public Bitmap get() throws IOException { + public ImageLoadResult get() throws IOException { long started = System.nanoTime(); checkNotMain(); @@ -604,7 +606,9 @@ private void performRemoteViewInto(RemoteViewsAction action) { if (!skipMemoryCache) { Bitmap bitmap = picasso.quickMemoryCacheCheck(action.getKey()); if (bitmap != null) { - action.complete(bitmap, MEMORY); + ImageLoadResult result = new ImageLoadResult(); + result.bitmap = bitmap; + action.complete(result, MEMORY); return; } } diff --git a/picasso/src/main/java/com/squareup/picasso/Target.java b/picasso/src/main/java/com/squareup/picasso/Target.java index b402db0..bf4ce45 100644 --- a/picasso/src/main/java/com/squareup/picasso/Target.java +++ b/picasso/src/main/java/com/squareup/picasso/Target.java @@ -15,6 +15,8 @@ */ package com.squareup.picasso; +import java.io.InputStream; + import android.graphics.Bitmap; import android.graphics.drawable.Drawable; @@ -49,9 +51,12 @@ public interface Target { /** * Callback invoked right before your request is submitted. *

- * Note: The passed {@link Drawable} may be {@code null} if none has been - * specified via {@link RequestCreator#placeholder(android.graphics.drawable.Drawable)} - * or {@link RequestCreator#placeholder(int)}. + * Note: The passed {@link Drawable} may be {@code null} if none has + * been specified via + * {@link RequestCreator#placeholder(android.graphics.drawable.Drawable)} or + * {@link RequestCreator#placeholder(int)}. */ void onPrepareLoad(Drawable placeHolderDrawable); + + void onGifStreamAvailable(InputStream stream, LoadedFrom from); } diff --git a/picasso/src/main/java/com/squareup/picasso/TargetAction.java b/picasso/src/main/java/com/squareup/picasso/TargetAction.java index 5100ad9..4c67f52 100644 --- a/picasso/src/main/java/com/squareup/picasso/TargetAction.java +++ b/picasso/src/main/java/com/squareup/picasso/TargetAction.java @@ -15,26 +15,33 @@ */ package com.squareup.picasso; -import android.graphics.Bitmap; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; + import android.graphics.drawable.Drawable; final class TargetAction extends Action { - TargetAction(Picasso picasso, Target target, Request data, boolean skipCache, - int errorResId, Drawable errorDrawable, String key, Object tag) { + TargetAction(Picasso picasso, Target target, Request data, boolean skipCache, int errorResId, + Drawable errorDrawable, String key, Object tag) { super(picasso, target, data, skipCache, false, errorResId, errorDrawable, key, tag); } - @Override void complete(Bitmap result, Picasso.LoadedFrom from) { + @Override void complete(ImageLoadResult result, Picasso.LoadedFrom from) { if (result == null) { - throw new AssertionError( - String.format("Attempted to complete action with no result!\n%s", this)); + throw new AssertionError(String.format("Attempted to complete action with no result!\n%s", + this)); } Target target = getTarget(); if (target != null) { - target.onBitmapLoaded(result, from); - if (result.isRecycled()) { - throw new IllegalStateException("Target callback must not recycle bitmap!"); + if (result.bitmap != null) { + target.onBitmapLoaded(result.bitmap, from); + if (result.bitmap.isRecycled()) { + throw new IllegalStateException("Target callback must not recycle bitmap!"); + } + } else if (result.gifStream != null) { + target.onGifStreamAvailable(result.gifStream, from); + } else { + error(); } } } diff --git a/picasso/src/test/java/com/squareup/picasso/BitmapHunterTest.java b/picasso/src/test/java/com/squareup/picasso/BitmapHunterTest.java index c6ffc60..d49518d 100644 --- a/picasso/src/test/java/com/squareup/picasso/BitmapHunterTest.java +++ b/picasso/src/test/java/com/squareup/picasso/BitmapHunterTest.java @@ -151,7 +151,7 @@ public class BitmapHunterTest { TestableBitmapHunter hunter = new TestableBitmapHunter(picasso, dispatcher, cache, stats, action, BITMAP_1); - Bitmap result = hunter.hunt(); + Bitmap result = hunter.hunt().bitmap; verify(cache).get(URI_KEY_1); verify(hunter.requestHandler).load(action.getRequest()); assertThat(result).isEqualTo(BITMAP_1); @@ -163,7 +163,7 @@ public class BitmapHunterTest { TestableBitmapHunter hunter = new TestableBitmapHunter(picasso, dispatcher, cache, stats, action, BITMAP_1); - Bitmap result = hunter.hunt(); + Bitmap result = hunter.hunt().bitmap; verify(cache).get(URI_KEY_1); verify(hunter.requestHandler, never()).load(action.getRequest()); assertThat(result).isEqualTo(BITMAP_1); @@ -182,7 +182,7 @@ public class BitmapHunterTest { Action action = mockAction(CUSTOM_URI_KEY, CUSTOM_URI); BitmapHunter hunter = forRequest(mockPicasso(new CustomRequestHandler()), dispatcher, cache, stats, action); - Bitmap result = hunter.hunt(); + Bitmap result = hunter.hunt().bitmap; assertThat(result).isEqualTo(BITMAP_1); } diff --git a/picasso/src/test/java/com/squareup/picasso/DispatcherTest.java b/picasso/src/test/java/com/squareup/picasso/DispatcherTest.java index 653da4e..3487aa9 100644 --- a/picasso/src/test/java/com/squareup/picasso/DispatcherTest.java +++ b/picasso/src/test/java/com/squareup/picasso/DispatcherTest.java @@ -175,7 +175,7 @@ public class DispatcherTest { @Test public void performCompleteSetsResultInCache() throws Exception { BitmapHunter hunter = mockHunter(URI_KEY_1, BITMAP_1, false); dispatcher.performComplete(hunter); - verify(cache).set(hunter.getKey(), hunter.getResult()); + verify(cache).set(hunter.getKey(), hunter.getResult().bitmap); } @Test public void performCompleteWithSkipCacheDoesNotCache() throws Exception { diff --git a/picasso/src/test/java/com/squareup/picasso/ImageViewActionTest.java b/picasso/src/test/java/com/squareup/picasso/ImageViewActionTest.java index a0ef090..cda1b1f 100644 --- a/picasso/src/test/java/com/squareup/picasso/ImageViewActionTest.java +++ b/picasso/src/test/java/com/squareup/picasso/ImageViewActionTest.java @@ -23,6 +23,8 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; + import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY; import static com.squareup.picasso.Picasso.RequestTransformer.IDENTITY; import static com.squareup.picasso.TestUtils.BITMAP_1; @@ -56,7 +58,7 @@ public void returnsIfTargetIsNullOnComplete() throws Exception { ImageViewAction request = new ImageViewAction(picasso, target, null, false, false, 0, null, URI_KEY_1, null, callback); request.target.clear(); - request.complete(BITMAP_1, MEMORY); + request.complete(new ImageLoadResult(BITMAP_1), MEMORY); verifyZeroInteractions(target); verifyZeroInteractions(callback); } @@ -83,7 +85,7 @@ public void invokesTargetAndCallbackSuccessIfTargetIsNotNull() throws Exception Callback callback = mockCallback(); ImageViewAction request = new ImageViewAction(picasso, target, null, false, false, 0, null, URI_KEY_1, null, callback); - request.complete(BITMAP_1, MEMORY); + request.complete(new ImageLoadResult(BITMAP_1), MEMORY); verify(target).setImageDrawable(any(PicassoDrawable.class)); verify(callback).onSuccess(); } diff --git a/picasso/src/test/java/com/squareup/picasso/PicassoTest.java b/picasso/src/test/java/com/squareup/picasso/PicassoTest.java index 0041c65..dee358f 100644 --- a/picasso/src/test/java/com/squareup/picasso/PicassoTest.java +++ b/picasso/src/test/java/com/squareup/picasso/PicassoTest.java @@ -30,6 +30,8 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; + import static com.squareup.picasso.Picasso.Listener; import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY; import static com.squareup.picasso.RemoteViewsAction.RemoteViewsTarget; @@ -120,8 +122,8 @@ public class PicassoTest { when(hunter.getActions()).thenReturn(Arrays.asList(action1, action2)); when(hunter.getLoadedFrom()).thenReturn(MEMORY); picasso.complete(hunter); - verify(action1).complete(BITMAP_1, MEMORY); - verify(action2, never()).complete(eq(BITMAP_1), any(Picasso.LoadedFrom.class)); + verify(action1).complete(new ImageLoadResult(BITMAP_1), MEMORY); + verify(action2, never()).complete(new ImageLoadResult(eq(BITMAP_1)), any(Picasso.LoadedFrom.class)); } @Test public void completeInvokesErrorOnAllFailedRequests() throws Exception { @@ -144,7 +146,7 @@ public class PicassoTest { when(hunter.getAction()).thenReturn(action); when(hunter.getActions()).thenReturn(Collections.emptyList()); picasso.complete(hunter); - verify(action).complete(BITMAP_1, MEMORY); + verify(action).complete(new ImageLoadResult(BITMAP_1), MEMORY); } @Test public void completeWithReplayDoesNotRemove() throws Exception { @@ -157,7 +159,7 @@ public class PicassoTest { assertThat(picasso.targetToAction).hasSize(1); picasso.complete(hunter); assertThat(picasso.targetToAction).hasSize(1); - verify(action).complete(BITMAP_1, MEMORY); + verify(action).complete(new ImageLoadResult(BITMAP_1), MEMORY); } @Test public void completeDeliversToSingleAndMultiple() throws Exception { @@ -168,8 +170,8 @@ public class PicassoTest { when(hunter.getAction()).thenReturn(action); when(hunter.getActions()).thenReturn(Arrays.asList(action2)); picasso.complete(hunter); - verify(action).complete(BITMAP_1, MEMORY); - verify(action2).complete(BITMAP_1, MEMORY); + verify(action).complete(new ImageLoadResult(BITMAP_1), MEMORY); + verify(action2).complete(new ImageLoadResult(BITMAP_1), MEMORY); } @Test public void completeSkipsIfNoActions() throws Exception { @@ -205,7 +207,7 @@ public class PicassoTest { when(cache.get(URI_KEY_1)).thenReturn(BITMAP_1); Action action = mockAction(URI_KEY_1, URI_1); picasso.resumeAction(action); - verify(action).complete(BITMAP_1, MEMORY); + verify(action).complete(new ImageLoadResult(BITMAP_1), MEMORY); } @Test public void cancelExistingRequestWithUnknownTarget() throws Exception { diff --git a/picasso/src/test/java/com/squareup/picasso/RemoteViewsActionTest.java b/picasso/src/test/java/com/squareup/picasso/RemoteViewsActionTest.java index 715a6e1..cf680b9 100644 --- a/picasso/src/test/java/com/squareup/picasso/RemoteViewsActionTest.java +++ b/picasso/src/test/java/com/squareup/picasso/RemoteViewsActionTest.java @@ -24,6 +24,8 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; + import static com.squareup.picasso.Picasso.LoadedFrom.NETWORK; import static com.squareup.picasso.Picasso.RequestTransformer.IDENTITY; import static com.squareup.picasso.TestUtils.BITMAP_1; @@ -48,7 +50,7 @@ public class RemoteViewsActionTest { @Test public void completeSetsBitmapOnRemoteViews() throws Exception { RemoteViewsAction action = createAction(); - action.complete(BITMAP_1, NETWORK); + action.complete(new ImageLoadResult(BITMAP_1), NETWORK); verify(remoteViews).setImageViewBitmap(1, BITMAP_1); } diff --git a/picasso/src/test/java/com/squareup/picasso/RequestCreatorTest.java b/picasso/src/test/java/com/squareup/picasso/RequestCreatorTest.java index 8ff961a..c3f9f95 100644 --- a/picasso/src/test/java/com/squareup/picasso/RequestCreatorTest.java +++ b/picasso/src/test/java/com/squareup/picasso/RequestCreatorTest.java @@ -104,7 +104,7 @@ public void getOnMainCrashes() throws Exception { new Thread(new Runnable() { @Override public void run() { try { - result[0] = new RequestCreator(picasso, null, 0).get(); + result[0] = new RequestCreator(picasso, null, 0).get().bitmap; } catch (IOException e) { fail(e.getMessage()); } finally { diff --git a/picasso/src/test/java/com/squareup/picasso/TargetActionTest.java b/picasso/src/test/java/com/squareup/picasso/TargetActionTest.java index 82429c2..8a65937 100644 --- a/picasso/src/test/java/com/squareup/picasso/TargetActionTest.java +++ b/picasso/src/test/java/com/squareup/picasso/TargetActionTest.java @@ -15,6 +15,8 @@ */ package com.squareup.picasso; +import java.io.InputStream; + import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; @@ -24,6 +26,9 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; +import com.squareup.picasso.Picasso.LoadedFrom; + import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY; import static com.squareup.picasso.Picasso.RequestTransformer.IDENTITY; import static com.squareup.picasso.TestUtils.BITMAP_1; @@ -52,7 +57,7 @@ public void invokesSuccessIfTargetIsNotNull() throws Exception { Target target = mockTarget(); TargetAction request = new TargetAction(mock(Picasso.class), target, null, false, 0, null, URI_KEY_1, null); - request.complete(BITMAP_3, MEMORY); + request.complete(new ImageLoadResult(BITMAP_3), MEMORY); verify(target).onBitmapLoaded(BITMAP_3, MEMORY); } @@ -89,6 +94,10 @@ public void invokesOnBitmapFailedIfTargetIsNotNullWithErrorResourceId() throws E @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { bitmap.recycle(); } + + @Override public void onGifStreamAvailable(InputStream stream, LoadedFrom from) { + throw new AssertionError(); + } @Override public void onBitmapFailed(Drawable errorDrawable) { throw new AssertionError(); @@ -102,7 +111,7 @@ public void invokesOnBitmapFailedIfTargetIsNotNullWithErrorResourceId() throws E TargetAction tr = new TargetAction(picasso, bad, null, false, 0, null, URI_KEY_1, null); try { - tr.complete(BITMAP_1, MEMORY); + tr.complete(new ImageLoadResult(BITMAP_1), MEMORY); fail(); } catch (IllegalStateException expected) { } diff --git a/picasso/src/test/java/com/squareup/picasso/TestUtils.java b/picasso/src/test/java/com/squareup/picasso/TestUtils.java index 68da364..c1c92ee 100644 --- a/picasso/src/test/java/com/squareup/picasso/TestUtils.java +++ b/picasso/src/test/java/com/squareup/picasso/TestUtils.java @@ -32,6 +32,8 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import com.squareup.picasso.BitmapHunter.ImageLoadResult; + import static android.content.ContentResolver.SCHEME_ANDROID_RESOURCE; import static android.provider.ContactsContract.Contacts.CONTENT_URI; import static android.provider.ContactsContract.Contacts.Photo.CONTENT_DIRECTORY; @@ -225,7 +227,7 @@ static BitmapHunter mockHunter(String key, Bitmap result, boolean skipCache, Act Request data = new Request.Builder(URI_1).build(); BitmapHunter hunter = mock(BitmapHunter.class); when(hunter.getKey()).thenReturn(key); - when(hunter.getResult()).thenReturn(result); + when(hunter.getResult()).thenReturn(new ImageLoadResult(result)); when(hunter.getData()).thenReturn(data); when(hunter.shouldSkipMemoryCache()).thenReturn(skipCache); when(hunter.getAction()).thenReturn(action); From 8dd9320b087c6fb356265508fb22228c7ff1e037 Mon Sep 17 00:00:00 2001 From: billdawson Date: Tue, 30 Sep 2014 20:55:22 +0200 Subject: [PATCH 3/8] Re-factor gif checking somewhat For better re-use when dealing with File sources. --- .../picasso/NetworkRequestHandler.java | 38 ++++++------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java b/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java index 442b009..b4fe6cf 100644 --- a/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java @@ -37,14 +37,7 @@ class NetworkRequestHandler extends RequestHandler { private final Downloader downloader; private final Stats stats; - static class DecodeResult { - /** - * If null, check isGif and inputStream. - */ - Bitmap bitmap; - /** - * Null if bitmap is non-null. Used only for a GIF stream. - */ + static class GifPrecheckResult { InputStream inputStream; boolean isGif; } @@ -89,12 +82,13 @@ public NetworkRequestHandler(Downloader downloader, Stats stats) { boolean isGif = false; try { - DecodeResult result = decodeWithGifRecognition(is, data); + GifPrecheckResult result = precheckForGif(is); isGif = result.isGif; if (isGif) { return new Result(result.inputStream, loadedFrom); + } else { + return new Result(decodeStream(result.inputStream, data), loadedFrom); } - return new Result(result.bitmap, loadedFrom); } finally { if (!isGif) { Utils.closeQuietly(is); @@ -115,37 +109,29 @@ public NetworkRequestHandler(Downloader downloader, Stats stats) { } /** - * Will check first if stream is GIF. If so, will put the stream in the result and - * return immediately. If not, calls {@link #decodeStream(InputStream, Request)} and - * puts resulting bitmap in result. + * Determines if stream is GIF. The stream saved in the returned + * {@link GifPrecheckResult#inputStream} member should be used for all subsequent + * operations, because this method reads the first few bytes and therefore creates a + * markable stream from the passed-in stream. * * @param stream - * @param data - * @return {@link DecodeResult} + * @return {@link GifPrecheckResult} * @throws IOException */ - private DecodeResult decodeWithGifRecognition(InputStream stream, Request data) + private GifPrecheckResult precheckForGif(InputStream stream) throws IOException { + GifPrecheckResult result = new GifPrecheckResult(); MarkableInputStream markStream; if (stream instanceof MarkableInputStream) { markStream = (MarkableInputStream) stream; } else { markStream = new MarkableInputStream(stream); } + result.inputStream = markStream; long mark = markStream.savePosition(MARKER); - DecodeResult result = new DecodeResult(); result.isGif = Utils.isGifFile(markStream); markStream.reset(mark); - - if (result.isGif) { - result.bitmap = null; - result.inputStream = markStream; - } else { - result.bitmap = decodeStream(markStream, data); - result.inputStream = null; - } - return result; } From d0fbb6a0e00c5e3d611c65b512a4711230a76442 Mon Sep 17 00:00:00 2001 From: billdawson Date: Tue, 30 Sep 2014 21:06:16 +0200 Subject: [PATCH 4/8] Further gif check refactoring --- .../picasso/NetworkRequestHandler.java | 33 ------------- .../com/squareup/picasso/RequestHandler.java | 48 +++++++++++++++++++ 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java b/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java index b4fe6cf..213414b 100644 --- a/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/NetworkRequestHandler.java @@ -29,7 +29,6 @@ class NetworkRequestHandler extends RequestHandler { static final int RETRY_COUNT = 2; - private static final int MARKER = 65536; private static final String SCHEME_HTTP = "http"; private static final String SCHEME_HTTPS = "https"; @@ -37,11 +36,6 @@ class NetworkRequestHandler extends RequestHandler { private final Downloader downloader; private final Stats stats; - static class GifPrecheckResult { - InputStream inputStream; - boolean isGif; - } - public NetworkRequestHandler(Downloader downloader, Stats stats) { this.downloader = downloader; this.stats = stats; @@ -108,33 +102,6 @@ public NetworkRequestHandler(Downloader downloader, Stats stats) { return true; } - /** - * Determines if stream is GIF. The stream saved in the returned - * {@link GifPrecheckResult#inputStream} member should be used for all subsequent - * operations, because this method reads the first few bytes and therefore creates a - * markable stream from the passed-in stream. - * - * @param stream - * @return {@link GifPrecheckResult} - * @throws IOException - */ - private GifPrecheckResult precheckForGif(InputStream stream) - throws IOException { - GifPrecheckResult result = new GifPrecheckResult(); - MarkableInputStream markStream; - if (stream instanceof MarkableInputStream) { - markStream = (MarkableInputStream) stream; - } else { - markStream = new MarkableInputStream(stream); - } - result.inputStream = markStream; - - long mark = markStream.savePosition(MARKER); - result.isGif = Utils.isGifFile(markStream); - markStream.reset(mark); - return result; - } - private Bitmap decodeStream(InputStream stream, Request data) throws IOException { MarkableInputStream markStream; diff --git a/picasso/src/main/java/com/squareup/picasso/RequestHandler.java b/picasso/src/main/java/com/squareup/picasso/RequestHandler.java index 32a206b..6358b05 100644 --- a/picasso/src/main/java/com/squareup/picasso/RequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/RequestHandler.java @@ -46,6 +46,26 @@ * @see Picasso.Builder#addRequestHandler(RequestHandler) */ public abstract class RequestHandler { + protected static final int MARKER = 65536; + + /** + * Represents the result of a {@link RequestHandler#precheckForGif(InputStream)} call. + * @author bill + * + */ + protected static class GifPrecheckResult { + /** + * The stream that was checked for being a GIF, or a wrapped version of the + * same if it was not markable. A markable stream is required since the first few + * bytes are read then the stream is reset so that future decoding operations can + * succeed. Therefore callers to {@link RequestHandler#precheckForGif(InputStream)} + * should use this returned instance of the stream to be sure to avoid any exceptions + * concerning trying to reset an unmarkable stream. + */ + InputStream inputStream; + boolean isGif; + } + /** * {@link Result} represents the result of a {@link #load(Request)} call in a * {@link RequestHandler}. @@ -186,4 +206,32 @@ static void calculateInSampleSize(int reqWidth, int reqHeight, int width, int he options.inSampleSize = sampleSize; options.inJustDecodeBounds = false; } + + /** + * Determines if stream contains a GIF image. The stream saved in the returned + * {@link GifPrecheckResult#inputStream} member should be used for all subsequent + * operations, because this method reads the first few bytes and therefore creates a + * markable stream from the passed-in stream. + * + * @param stream + * @return {@link GifPrecheckResult} + * @throws IOException + */ + protected GifPrecheckResult precheckForGif(InputStream stream) + throws IOException { + GifPrecheckResult result = new GifPrecheckResult(); + MarkableInputStream markStream; + if (stream instanceof MarkableInputStream) { + markStream = (MarkableInputStream) stream; + } else { + markStream = new MarkableInputStream(stream); + } + result.inputStream = markStream; + + long mark = markStream.savePosition(MARKER); + result.isGif = Utils.isGifFile(markStream); + markStream.reset(mark); + return result; + } + } From eda648e7979795936c786665b122bfa0262c922b Mon Sep 17 00:00:00 2001 From: billdawson Date: Tue, 30 Sep 2014 21:19:21 +0200 Subject: [PATCH 5/8] Further refactor for gif preparation for content streams --- .../picasso/ContentStreamRequestHandler.java | 9 ++++++--- .../com/squareup/picasso/FileRequestHandler.java | 2 +- .../squareup/picasso/MediaStoreRequestHandler.java | 4 ++-- .../java/com/squareup/picasso/RequestHandler.java | 13 ++++++++++++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java b/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java index 3dd0784..2fc0a2d 100644 --- a/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java @@ -22,6 +22,8 @@ import java.io.IOException; import java.io.InputStream; +import com.squareup.picasso.Picasso.LoadedFrom; + import static android.content.ContentResolver.SCHEME_CONTENT; import static com.squareup.picasso.Picasso.LoadedFrom.DISK; @@ -37,10 +39,10 @@ class ContentStreamRequestHandler extends RequestHandler { } @Override public Result load(Request data) throws IOException { - return new Result(decodeContentStream(data), DISK); + return decodeContentStream(data, DISK, /* exifOrientation */ 0); } - protected Bitmap decodeContentStream(Request data) throws IOException { + protected Result decodeContentStream(Request data, LoadedFrom loadedFrom, int exifOrientation) throws IOException { ContentResolver contentResolver = context.getContentResolver(); final BitmapFactory.Options options = createBitmapOptions(data); if (requiresInSampleSize(options)) { @@ -55,7 +57,8 @@ protected Bitmap decodeContentStream(Request data) throws IOException { } InputStream is = contentResolver.openInputStream(data.uri); try { - return BitmapFactory.decodeStream(is, null, options); + Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); + return new Result(bitmap, loadedFrom, exifOrientation); } finally { Utils.closeQuietly(is); } diff --git a/picasso/src/main/java/com/squareup/picasso/FileRequestHandler.java b/picasso/src/main/java/com/squareup/picasso/FileRequestHandler.java index 5202e30..027a20c 100644 --- a/picasso/src/main/java/com/squareup/picasso/FileRequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/FileRequestHandler.java @@ -39,7 +39,7 @@ class FileRequestHandler extends ContentStreamRequestHandler { } @Override public Result load(Request data) throws IOException { - return new Result(decodeContentStream(data), DISK, getFileExifRotation(data.uri)); + return decodeContentStream(data, DISK, getFileExifRotation(data.uri)); } static int getFileExifRotation(Uri uri) throws IOException { diff --git a/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java b/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java index 4fba2f2..c01f1c8 100644 --- a/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java @@ -61,7 +61,7 @@ class MediaStoreRequestHandler extends ContentStreamRequestHandler { if (data.hasSize()) { PicassoKind picassoKind = getPicassoKind(data.targetWidth, data.targetHeight); if (!isVideo && picassoKind == FULL) { - return new Result(decodeContentStream(data), DISK, exifOrientation); + return decodeContentStream(data, DISK, exifOrientation); } long id = parseId(data.uri); @@ -89,7 +89,7 @@ class MediaStoreRequestHandler extends ContentStreamRequestHandler { } } - return new Result(decodeContentStream(data), DISK, exifOrientation); + return decodeContentStream(data, DISK, exifOrientation); } static PicassoKind getPicassoKind(int targetWidth, int targetHeight) { diff --git a/picasso/src/main/java/com/squareup/picasso/RequestHandler.java b/picasso/src/main/java/com/squareup/picasso/RequestHandler.java index 6358b05..5697b25 100644 --- a/picasso/src/main/java/com/squareup/picasso/RequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/RequestHandler.java @@ -90,10 +90,21 @@ public Result(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) { * @param loadedFrom {@link LoadedFrom}. */ public Result(InputStream gifStream, Picasso.LoadedFrom loadedFrom) { + this(gifStream, loadedFrom, 0); + } + + /** + * Use only when stream has been identified as containing GIF data. + * + * @param gifStream {@link InputStream} containing GIF data. + * @param loadedFrom {@link LoadedFrom}. + * @param exifOrientation + */ + public Result(InputStream gifStream, Picasso.LoadedFrom loadedFrom, int exifOrientation) { this.gifStream = gifStream; this.bitmap = null; this.loadedFrom = loadedFrom; - this.exifOrientation = 0; + this.exifOrientation = exifOrientation; } Result(Bitmap bitmap, Picasso.LoadedFrom loadedFrom, int exifOrientation) { From e3ac96b10f056a5a275e567a739264d8e2520012 Mon Sep 17 00:00:00 2001 From: billdawson Date: Tue, 30 Sep 2014 22:05:07 +0200 Subject: [PATCH 6/8] Do gif prechecks on content stream requests --- .../squareup/picasso/ContentStreamRequestHandler.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java b/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java index 2fc0a2d..23eb093 100644 --- a/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java @@ -49,6 +49,11 @@ protected Result decodeContentStream(Request data, LoadedFrom loadedFrom, int ex InputStream is = null; try { is = contentResolver.openInputStream(data.uri); + GifPrecheckResult precheck = precheckForGif(is); + if (precheck.isGif) { + return new Result(precheck.inputStream, loadedFrom); + } + is = precheck.inputStream; BitmapFactory.decodeStream(is, null, options); } finally { Utils.closeQuietly(is); @@ -56,6 +61,11 @@ protected Result decodeContentStream(Request data, LoadedFrom loadedFrom, int ex calculateInSampleSize(data.targetWidth, data.targetHeight, options, data); } InputStream is = contentResolver.openInputStream(data.uri); + GifPrecheckResult precheck = precheckForGif(is); + if (precheck.isGif) { + return new Result(precheck.inputStream, loadedFrom); + } + is = precheck.inputStream; try { Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); return new Result(bitmap, loadedFrom, exifOrientation); From 81aba99c6287b567ac741d93662cb2249061d0c2 Mon Sep 17 00:00:00 2001 From: billdawson Date: Tue, 30 Sep 2014 22:36:58 +0200 Subject: [PATCH 7/8] Fix style problems --- .../picasso/ContentStreamRequestHandler.java | 3 ++- .../com/squareup/picasso/RequestHandler.java | 18 ++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java b/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java index 23eb093..525bd66 100644 --- a/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/ContentStreamRequestHandler.java @@ -42,7 +42,8 @@ class ContentStreamRequestHandler extends RequestHandler { return decodeContentStream(data, DISK, /* exifOrientation */ 0); } - protected Result decodeContentStream(Request data, LoadedFrom loadedFrom, int exifOrientation) throws IOException { + protected Result decodeContentStream(Request data, LoadedFrom loadedFrom, int exifOrientation) + throws IOException { ContentResolver contentResolver = context.getContentResolver(); final BitmapFactory.Options options = createBitmapOptions(data); if (requiresInSampleSize(options)) { diff --git a/picasso/src/main/java/com/squareup/picasso/RequestHandler.java b/picasso/src/main/java/com/squareup/picasso/RequestHandler.java index 5697b25..39d26e1 100644 --- a/picasso/src/main/java/com/squareup/picasso/RequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/RequestHandler.java @@ -22,8 +22,6 @@ import android.graphics.BitmapFactory; import android.net.NetworkInfo; -import com.squareup.picasso.Picasso.LoadedFrom; - /** * {@link RequestHandler} allows you to extend Picasso to load images in ways * that are not supported by default in the library. @@ -34,15 +32,15 @@ * override two methods ({@link #canHandleRequest(Request)} and * {@link #load(Request)}) with your custom logic to load images. *

- * + * *

* You should then register your {@link RequestHandler} using * {@link Picasso.Builder#addRequestHandler(RequestHandler)} *

- * + * * NOTE: This is a beta feature. The API is subject to change in a * backwards incompatible way at any time. - * + * * @see Picasso.Builder#addRequestHandler(RequestHandler) */ public abstract class RequestHandler { @@ -69,7 +67,7 @@ protected static class GifPrecheckResult { /** * {@link Result} represents the result of a {@link #load(Request)} call in a * {@link RequestHandler}. - * + * * @see RequestHandler * @see #load(Request) */ @@ -85,7 +83,7 @@ public Result(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) { /** * Use only when stream has been identified as containing GIF data. - * + * * @param gifStream {@link InputStream} containing GIF data. * @param loadedFrom {@link LoadedFrom}. */ @@ -95,7 +93,7 @@ public Result(InputStream gifStream, Picasso.LoadedFrom loadedFrom) { /** * Use only when stream has been identified as containing GIF data. - * + * * @param gifStream {@link InputStream} containing GIF data. * @param loadedFrom {@link LoadedFrom}. * @param exifOrientation @@ -159,7 +157,7 @@ int getExifOrientation() { /** * Loads an image for the given {@link Request}. - * + * * @param data the {@link android.net.Uri} to load the image from. * @return A {@link Result} instance representing the result. */ @@ -223,7 +221,7 @@ static void calculateInSampleSize(int reqWidth, int reqHeight, int width, int he * {@link GifPrecheckResult#inputStream} member should be used for all subsequent * operations, because this method reads the first few bytes and therefore creates a * markable stream from the passed-in stream. - * + * * @param stream * @return {@link GifPrecheckResult} * @throws IOException From dd4c66b620b69c9236c6afcef23b03db731b8b46 Mon Sep 17 00:00:00 2001 From: billdawson Date: Tue, 30 Sep 2014 22:54:55 +0200 Subject: [PATCH 8/8] Change visibility of ImageLoadResult --- .../java/com/squareup/picasso/Action.java | 1 - .../com/squareup/picasso/BitmapHunter.java | 15 ------------- .../java/com/squareup/picasso/Dispatcher.java | 2 -- .../com/squareup/picasso/FetchAction.java | 2 -- .../java/com/squareup/picasso/GetAction.java | 2 -- .../com/squareup/picasso/ImageLoadResult.java | 22 +++++++++++++++++++ .../com/squareup/picasso/ImageViewAction.java | 2 -- .../java/com/squareup/picasso/Picasso.java | 2 -- .../squareup/picasso/RemoteViewsAction.java | 2 -- .../com/squareup/picasso/RequestCreator.java | 2 -- .../com/squareup/picasso/TargetAction.java | 2 -- .../squareup/picasso/ImageViewActionTest.java | 2 +- .../com/squareup/picasso/PicassoTest.java | 2 +- .../picasso/RemoteViewsActionTest.java | 2 +- .../squareup/picasso/TargetActionTest.java | 2 +- .../java/com/squareup/picasso/TestUtils.java | 2 +- 16 files changed, 27 insertions(+), 37 deletions(-) create mode 100644 picasso/src/main/java/com/squareup/picasso/ImageLoadResult.java diff --git a/picasso/src/main/java/com/squareup/picasso/Action.java b/picasso/src/main/java/com/squareup/picasso/Action.java index 669fd21..d26423d 100644 --- a/picasso/src/main/java/com/squareup/picasso/Action.java +++ b/picasso/src/main/java/com/squareup/picasso/Action.java @@ -17,7 +17,6 @@ import android.graphics.drawable.Drawable; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; import com.squareup.picasso.Picasso.Priority; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; diff --git a/picasso/src/main/java/com/squareup/picasso/BitmapHunter.java b/picasso/src/main/java/com/squareup/picasso/BitmapHunter.java index 054c2ad..635ab98 100644 --- a/picasso/src/main/java/com/squareup/picasso/BitmapHunter.java +++ b/picasso/src/main/java/com/squareup/picasso/BitmapHunter.java @@ -19,7 +19,6 @@ import android.graphics.Matrix; import android.net.NetworkInfo; import java.io.IOException; -import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; @@ -40,20 +39,6 @@ import static com.squareup.picasso.Utils.log; class BitmapHunter implements Runnable { - static class ImageLoadResult { - Bitmap bitmap; - InputStream gifStream; - - ImageLoadResult() { - this.bitmap = null; - this.gifStream = null; - } - - ImageLoadResult(Bitmap bitmap) { - this.bitmap = bitmap; - this.gifStream = null; - } - } /** * Global lock for bitmap decoding to ensure that we are only are decoding one at a diff --git a/picasso/src/main/java/com/squareup/picasso/Dispatcher.java b/picasso/src/main/java/com/squareup/picasso/Dispatcher.java index 9b56364..e144796 100644 --- a/picasso/src/main/java/com/squareup/picasso/Dispatcher.java +++ b/picasso/src/main/java/com/squareup/picasso/Dispatcher.java @@ -36,8 +36,6 @@ import java.util.WeakHashMap; import java.util.concurrent.ExecutorService; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; - import static android.content.Context.CONNECTIVITY_SERVICE; import static android.content.Intent.ACTION_AIRPLANE_MODE_CHANGED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; diff --git a/picasso/src/main/java/com/squareup/picasso/FetchAction.java b/picasso/src/main/java/com/squareup/picasso/FetchAction.java index 4ddaebd..df20c54 100644 --- a/picasso/src/main/java/com/squareup/picasso/FetchAction.java +++ b/picasso/src/main/java/com/squareup/picasso/FetchAction.java @@ -15,8 +15,6 @@ */ package com.squareup.picasso; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; - class FetchAction extends Action { FetchAction(Picasso picasso, Request data, boolean skipCache, String key, Object tag) { super(picasso, null, data, skipCache, false, 0, null, key, tag); diff --git a/picasso/src/main/java/com/squareup/picasso/GetAction.java b/picasso/src/main/java/com/squareup/picasso/GetAction.java index a928f29..4252e1b 100644 --- a/picasso/src/main/java/com/squareup/picasso/GetAction.java +++ b/picasso/src/main/java/com/squareup/picasso/GetAction.java @@ -15,8 +15,6 @@ */ package com.squareup.picasso; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; - class GetAction extends Action { GetAction(Picasso picasso, Request data, boolean skipCache, String key, Object tag) { super(picasso, null, data, skipCache, false, 0, null, key, tag); diff --git a/picasso/src/main/java/com/squareup/picasso/ImageLoadResult.java b/picasso/src/main/java/com/squareup/picasso/ImageLoadResult.java new file mode 100644 index 0000000..279d030 --- /dev/null +++ b/picasso/src/main/java/com/squareup/picasso/ImageLoadResult.java @@ -0,0 +1,22 @@ +package com.squareup.picasso; + +import java.io.InputStream; + +import android.graphics.Bitmap; + +public class ImageLoadResult { + + public Bitmap bitmap; + public InputStream gifStream; + + ImageLoadResult() { + this.bitmap = null; + this.gifStream = null; + } + + ImageLoadResult(Bitmap bitmap) { + this.bitmap = bitmap; + this.gifStream = null; + } + +} diff --git a/picasso/src/main/java/com/squareup/picasso/ImageViewAction.java b/picasso/src/main/java/com/squareup/picasso/ImageViewAction.java index 8ce7f77..3a747f9 100644 --- a/picasso/src/main/java/com/squareup/picasso/ImageViewAction.java +++ b/picasso/src/main/java/com/squareup/picasso/ImageViewAction.java @@ -19,8 +19,6 @@ import android.graphics.drawable.Drawable; import android.widget.ImageView; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; - class ImageViewAction extends Action { Callback callback; diff --git a/picasso/src/main/java/com/squareup/picasso/Picasso.java b/picasso/src/main/java/com/squareup/picasso/Picasso.java index 0d65e89..54ae38b 100644 --- a/picasso/src/main/java/com/squareup/picasso/Picasso.java +++ b/picasso/src/main/java/com/squareup/picasso/Picasso.java @@ -34,8 +34,6 @@ import java.util.WeakHashMap; import java.util.concurrent.ExecutorService; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; - import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static com.squareup.picasso.Action.RequestWeakReference; import static com.squareup.picasso.Dispatcher.HUNTER_BATCH_COMPLETE; diff --git a/picasso/src/main/java/com/squareup/picasso/RemoteViewsAction.java b/picasso/src/main/java/com/squareup/picasso/RemoteViewsAction.java index 4f9a310..539b0ab 100644 --- a/picasso/src/main/java/com/squareup/picasso/RemoteViewsAction.java +++ b/picasso/src/main/java/com/squareup/picasso/RemoteViewsAction.java @@ -15,8 +15,6 @@ */ package com.squareup.picasso; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; - import android.app.Notification; import android.app.NotificationManager; import android.appwidget.AppWidgetManager; diff --git a/picasso/src/main/java/com/squareup/picasso/RequestCreator.java b/picasso/src/main/java/com/squareup/picasso/RequestCreator.java index 8a6f74d..21498ff 100644 --- a/picasso/src/main/java/com/squareup/picasso/RequestCreator.java +++ b/picasso/src/main/java/com/squareup/picasso/RequestCreator.java @@ -28,8 +28,6 @@ import java.util.concurrent.atomic.AtomicInteger; import org.jetbrains.annotations.TestOnly; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; - import static com.squareup.picasso.BitmapHunter.forRequest; import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY; import static com.squareup.picasso.Picasso.Priority; diff --git a/picasso/src/main/java/com/squareup/picasso/TargetAction.java b/picasso/src/main/java/com/squareup/picasso/TargetAction.java index 4c67f52..cd44c68 100644 --- a/picasso/src/main/java/com/squareup/picasso/TargetAction.java +++ b/picasso/src/main/java/com/squareup/picasso/TargetAction.java @@ -15,8 +15,6 @@ */ package com.squareup.picasso; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; - import android.graphics.drawable.Drawable; final class TargetAction extends Action { diff --git a/picasso/src/test/java/com/squareup/picasso/ImageViewActionTest.java b/picasso/src/test/java/com/squareup/picasso/ImageViewActionTest.java index cda1b1f..e373a9d 100644 --- a/picasso/src/test/java/com/squareup/picasso/ImageViewActionTest.java +++ b/picasso/src/test/java/com/squareup/picasso/ImageViewActionTest.java @@ -23,7 +23,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; +import com.squareup.picasso.ImageLoadResult; import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY; import static com.squareup.picasso.Picasso.RequestTransformer.IDENTITY; diff --git a/picasso/src/test/java/com/squareup/picasso/PicassoTest.java b/picasso/src/test/java/com/squareup/picasso/PicassoTest.java index 73e2920..a1b4444 100644 --- a/picasso/src/test/java/com/squareup/picasso/PicassoTest.java +++ b/picasso/src/test/java/com/squareup/picasso/PicassoTest.java @@ -30,7 +30,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; +import com.squareup.picasso.ImageLoadResult; import static com.squareup.picasso.Picasso.Listener; import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY; diff --git a/picasso/src/test/java/com/squareup/picasso/RemoteViewsActionTest.java b/picasso/src/test/java/com/squareup/picasso/RemoteViewsActionTest.java index cf680b9..fb60e20 100644 --- a/picasso/src/test/java/com/squareup/picasso/RemoteViewsActionTest.java +++ b/picasso/src/test/java/com/squareup/picasso/RemoteViewsActionTest.java @@ -24,7 +24,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; +import com.squareup.picasso.ImageLoadResult; import static com.squareup.picasso.Picasso.LoadedFrom.NETWORK; import static com.squareup.picasso.Picasso.RequestTransformer.IDENTITY; diff --git a/picasso/src/test/java/com/squareup/picasso/TargetActionTest.java b/picasso/src/test/java/com/squareup/picasso/TargetActionTest.java index 8a65937..cf9a172 100644 --- a/picasso/src/test/java/com/squareup/picasso/TargetActionTest.java +++ b/picasso/src/test/java/com/squareup/picasso/TargetActionTest.java @@ -26,7 +26,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; +import com.squareup.picasso.ImageLoadResult; import com.squareup.picasso.Picasso.LoadedFrom; import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY; diff --git a/picasso/src/test/java/com/squareup/picasso/TestUtils.java b/picasso/src/test/java/com/squareup/picasso/TestUtils.java index c1c92ee..b33c7bb 100644 --- a/picasso/src/test/java/com/squareup/picasso/TestUtils.java +++ b/picasso/src/test/java/com/squareup/picasso/TestUtils.java @@ -32,7 +32,7 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import com.squareup.picasso.BitmapHunter.ImageLoadResult; +import com.squareup.picasso.ImageLoadResult; import static android.content.ContentResolver.SCHEME_ANDROID_RESOURCE; import static android.provider.ContactsContract.Contacts.CONTENT_URI;