From 700284ec94a2c78a6157a31dea1d70d0de51b9f1 Mon Sep 17 00:00:00 2001 From: Sam Judd Date: Sat, 28 Jun 2014 11:05:23 -0700 Subject: [PATCH] Make Volley an optional dependency --- .gitignore | 2 + README.md | 42 ++++- build.gradle | 6 +- integration/pom.xml | 19 +++ integration/volley/AndroidManifest.xml | 8 + integration/volley/build.gradle | 33 ++++ integration/volley/gradle.properties | 6 + integration/volley/lint.xml | 4 + integration/volley/pom.xml | 30 ++++ integration/volley/project.properties | 6 + .../glide/volley/RequestQueueWrapper.java | 5 + .../glide/volley/VolleyDiskCacheWrapper.java | 0 .../glide/volley/VolleyRequestFuture.java | 0 .../glide/volley/VolleyStreamFetcher.java | 0 .../glide/volley/VolleyUrlLoader.java | 0 library/build.gradle | 2 +- library/gradle.properties | 2 +- library/pom.xml | 5 +- .../main/java/com/bumptech/glide/Glide.java | 17 +- .../java/com/bumptech/glide/GlideBuilder.java | 14 +- .../com/bumptech/glide/RequestManager.java | 6 +- .../glide/load/data/HttpUrlFetcher.java | 88 ++++++++++ .../model/stream/HttpUrlGlideUrlLoader.java | 31 ++++ .../java/com/bumptech/glide/GlideTest.java | 54 ++---- .../glide/load/data/HttpUrlFetcherTest.java | 158 ++++++++++++++++++ .../stream/HttpUrlGlideUrlLoaderTest.java | 29 ++++ pom.xml | 6 +- samples/flickr/pom.xml | 8 +- .../samples/flickr/FlickrSearchActivity.java | 9 +- .../glide/samples/flickr/api/Api.java | 10 +- settings.gradle | 3 +- 31 files changed, 505 insertions(+), 98 deletions(-) create mode 100644 integration/pom.xml create mode 100644 integration/volley/AndroidManifest.xml create mode 100644 integration/volley/build.gradle create mode 100644 integration/volley/gradle.properties create mode 100644 integration/volley/lint.xml create mode 100644 integration/volley/pom.xml create mode 100644 integration/volley/project.properties rename {library => integration/volley}/src/main/java/com/bumptech/glide/volley/RequestQueueWrapper.java (91%) rename {library => integration/volley}/src/main/java/com/bumptech/glide/volley/VolleyDiskCacheWrapper.java (100%) rename {library => integration/volley}/src/main/java/com/bumptech/glide/volley/VolleyRequestFuture.java (100%) rename {library => integration/volley}/src/main/java/com/bumptech/glide/volley/VolleyStreamFetcher.java (100%) rename {library => integration/volley}/src/main/java/com/bumptech/glide/volley/VolleyUrlLoader.java (100%) create mode 100644 library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java create mode 100644 library/src/main/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoader.java create mode 100644 library/src/test/java/com/bumptech/glide/load/data/HttpUrlFetcherTest.java create mode 100644 library/src/test/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoaderTest.java diff --git a/.gitignore b/.gitignore index eee00ad02..07f3f1173 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ samples/flickr/out samples/flickr/bin samples/flickr/local.properties samples/flickr/target +integration/volley/target/** +**/local.properties *.keystore **/.idea/* .settings diff --git a/README.md b/README.md index 4a6509298..6310d6124 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,17 @@ Glide ===== -Glide is fast and efficient image loading library for Android that wraps image downloading, resizing, memory and disk caching, and bitmap recycling into one simple and easy to use interface. By default, Glide includes an implementation for fetching images over http based on Google's Volley project for fast, parallelized network operations on Android. +Glide is fast and efficient image loading library for Android that wraps image downloading, resizing, memory and disk +caching, and bitmap recycling into one simple and easy to use interface. Glide includes a flexible api allowing it to +plug in to almost any network stack. By default Glide uses a custom HttpUrlConnection based stack, but also includes a +utility library to plug in to Google's Volley project instead. -Glide's primary focus is on making scrolling any kind of a list of images as smooth and fast as possible, but Glide is also effective for almost any case where you need to fetch, resize, and display a remote image. +Glide's primary focus is on making scrolling any kind of a list of images as smooth and fast as possible, but Glide is +also effective for almost any case where you need to fetch, resize, and display a remote image. Download -------- -You can download a jar from GitHub's [release page](https://github.com/bumptech/glide/releases) or to use the 3.0 alpha branch, use Gradle: +You can download a jar from GitHub's [release page](https://github.com/bumptech/glide/releases) or to use the 3.0 alpha +branch, use Gradle: ```groovy repositories { @@ -38,12 +43,41 @@ In your module: ```xml com.github.bumptech.glide - glide + library 3.3.0-SNAPSHOT aar ``` +Volley +------- +Volley is now an optional dependency that can be included via a utility library. More utility libraries for other +projects will hopefully be coming soon. To use the utility library with Gradle, add: + +```groovy +dependencies { + compile group: 'com.github.bumptech.glide', name:'volley', version:'3.3.0-SNAPSHOT', changing:true + compile 'com.mcxiaoke.volley:library:1.0.+' +} +``` + +Or with maven: + +```xml + + com.github.bumptech.glide + volley + 3.3.0-SNAPSHOT + aar + + + com.mcxiaoke.volley + library + 1.0.5 + aar + +``` + How do I use Glide? ------------------- Checkout the GitHub wiki for pages on a variety of topics and links to javadocs. diff --git a/build.gradle b/build.gradle index 263cb08ac..018077280 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,9 @@ task wrapper(type: Wrapper) { gradleVersion = '1.10' } -evaluationDependsOnChildren(); +evaluationDependsOn(":integration:volley") +evaluationDependsOn(":third_party:gif_decoder") +evaluationDependsOn(":library") def getAndroidSdkDirectory() { project("library").android.sdkDirectory @@ -44,7 +46,7 @@ getAndroidLibraryVariants().each { variant -> task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) { // Get the variant from each subproject that matches our current variant's name. - def childEquivalentChildVariants = getAndroidChildren().collect { project -> + def childEquivalentChildVariants = getAndroidChildren().collect { project -> project.android.libraryVariants.findAll { type -> type.name == variant.name } }.sum() diff --git a/integration/pom.xml b/integration/pom.xml new file mode 100644 index 000000000..66241c2ef --- /dev/null +++ b/integration/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + + + com.github.bumptech.glide + glide-parent + 3.3.0-SNAPSHOT + ../pom.xml + + + glide-integration + pom + Glide Integration + + + volley + + diff --git a/integration/volley/AndroidManifest.xml b/integration/volley/AndroidManifest.xml new file mode 100644 index 000000000..b644aab74 --- /dev/null +++ b/integration/volley/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/integration/volley/build.gradle b/integration/volley/build.gradle new file mode 100644 index 000000000..c8ab369f0 --- /dev/null +++ b/integration/volley/build.gradle @@ -0,0 +1,33 @@ +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:0.11.2' + } +} + +apply plugin: 'android-library' + +repositories { + mavenCentral() +} + +dependencies { + compile project(':library') + + compile 'com.mcxiaoke.volley:library:1.0.+' +} + +android { + compileSdkVersion 19 + buildToolsVersion = '19.1.0' + sourceSets { + main { + java.srcDirs = ['src/main/java'] + manifest.srcFile 'AndroidManifest.xml' + } + } +} + +apply from: "https://raw.githubusercontent.com/mcxiaoke/gradle-mvn-push/master/gradle-mvn-push.gradle" diff --git a/integration/volley/gradle.properties b/integration/volley/gradle.properties new file mode 100644 index 000000000..0f9e81b57 --- /dev/null +++ b/integration/volley/gradle.properties @@ -0,0 +1,6 @@ +POM_NAME=Glide Volley Integration +POM_ARTIFACT_ID=glide-volley-integration +POM_PACKAGING=aar +POM_LICENCE_NAME=The Apache Software License, Version 2.0 +POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt +POM_LICENCE_DIST=repo diff --git a/integration/volley/lint.xml b/integration/volley/lint.xml new file mode 100644 index 000000000..d9d6c9fff --- /dev/null +++ b/integration/volley/lint.xml @@ -0,0 +1,4 @@ + + + + diff --git a/integration/volley/pom.xml b/integration/volley/pom.xml new file mode 100644 index 000000000..f1bf87251 --- /dev/null +++ b/integration/volley/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + + com.github.bumptech.glide + glide-integration + 3.3.0-SNAPSHOT + ../pom.xml + + + glide-volley-integration + aar + Glide Volley Integration + + + + com.github.bumptech.glide + library + 3.3.0-SNAPSHOT + aar + + + com.mcxiaoke.volley + library + 1.0.4 + + + + diff --git a/integration/volley/project.properties b/integration/volley/project.properties new file mode 100644 index 000000000..d226f51c6 --- /dev/null +++ b/integration/volley/project.properties @@ -0,0 +1,6 @@ +target=android-19 + +# https://code.google.com/p/android/issues/detail?id=40487 +renderscript.opt.level=O0 + +android.library=true diff --git a/library/src/main/java/com/bumptech/glide/volley/RequestQueueWrapper.java b/integration/volley/src/main/java/com/bumptech/glide/volley/RequestQueueWrapper.java similarity index 91% rename from library/src/main/java/com/bumptech/glide/volley/RequestQueueWrapper.java rename to integration/volley/src/main/java/com/bumptech/glide/volley/RequestQueueWrapper.java index 10333b94e..b31f44b15 100644 --- a/library/src/main/java/com/bumptech/glide/volley/RequestQueueWrapper.java +++ b/integration/volley/src/main/java/com/bumptech/glide/volley/RequestQueueWrapper.java @@ -12,10 +12,15 @@ import com.android.volley.toolbox.HttpClientStack; import com.android.volley.toolbox.HttpStack; import com.android.volley.toolbox.HurlStack; import com.android.volley.toolbox.NoCache; +import com.android.volley.toolbox.Volley; import com.bumptech.glide.load.engine.cache.DiskCache; import static android.content.pm.PackageManager.NameNotFoundException; +/** + * A clone of the {@link Volley#newRequestQueue(Context)} allowing the user to set a disk cache and defaulting to + * no disk cache. + */ public class RequestQueueWrapper { public static RequestQueue getRequestQueue(Context context) { diff --git a/library/src/main/java/com/bumptech/glide/volley/VolleyDiskCacheWrapper.java b/integration/volley/src/main/java/com/bumptech/glide/volley/VolleyDiskCacheWrapper.java similarity index 100% rename from library/src/main/java/com/bumptech/glide/volley/VolleyDiskCacheWrapper.java rename to integration/volley/src/main/java/com/bumptech/glide/volley/VolleyDiskCacheWrapper.java diff --git a/library/src/main/java/com/bumptech/glide/volley/VolleyRequestFuture.java b/integration/volley/src/main/java/com/bumptech/glide/volley/VolleyRequestFuture.java similarity index 100% rename from library/src/main/java/com/bumptech/glide/volley/VolleyRequestFuture.java rename to integration/volley/src/main/java/com/bumptech/glide/volley/VolleyRequestFuture.java diff --git a/library/src/main/java/com/bumptech/glide/volley/VolleyStreamFetcher.java b/integration/volley/src/main/java/com/bumptech/glide/volley/VolleyStreamFetcher.java similarity index 100% rename from library/src/main/java/com/bumptech/glide/volley/VolleyStreamFetcher.java rename to integration/volley/src/main/java/com/bumptech/glide/volley/VolleyStreamFetcher.java diff --git a/library/src/main/java/com/bumptech/glide/volley/VolleyUrlLoader.java b/integration/volley/src/main/java/com/bumptech/glide/volley/VolleyUrlLoader.java similarity index 100% rename from library/src/main/java/com/bumptech/glide/volley/VolleyUrlLoader.java rename to integration/volley/src/main/java/com/bumptech/glide/volley/VolleyUrlLoader.java diff --git a/library/build.gradle b/library/build.gradle index 0a8ed3e92..5d3507e22 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -73,7 +73,7 @@ android { } def getJarName() { - return "glide-${getVersionName()}.jar" + "glide-${getVersionName()}.jar" } // Build a jar, from http://stackoverflow.com/a/19037807/1002054. diff --git a/library/gradle.properties b/library/gradle.properties index afe754330..6f3b84292 100644 --- a/library/gradle.properties +++ b/library/gradle.properties @@ -1,3 +1,3 @@ POM_NAME=Glide Library -POM_ARTIFACT_ID=glide +POM_ARTIFACT_ID=library POM_PACKAGING=aar diff --git a/library/pom.xml b/library/pom.xml index 9402581f6..63154ab84 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -9,7 +9,7 @@ ../pom.xml - glide + library aar Glide Library @@ -56,9 +56,10 @@ test - com.bumptech.glide + com.github.bumptech.glide glide-gif-decoder 3.3.0-SNAPSHOT + aar diff --git a/library/src/main/java/com/bumptech/glide/Glide.java b/library/src/main/java/com/bumptech/glide/Glide.java index cbe320038..1ab0d0039 100644 --- a/library/src/main/java/com/bumptech/glide/Glide.java +++ b/library/src/main/java/com/bumptech/glide/Glide.java @@ -14,7 +14,6 @@ import android.support.v4.app.FragmentActivity; import android.util.Log; import android.view.View; import android.widget.ImageView; -import com.android.volley.RequestQueue; import com.bumptech.glide.load.engine.Engine; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.engine.cache.DiskCache; @@ -29,6 +28,7 @@ import com.bumptech.glide.load.model.file_descriptor.FileDescriptorModelLoader; import com.bumptech.glide.load.model.file_descriptor.FileDescriptorResourceLoader; import com.bumptech.glide.load.model.file_descriptor.FileDescriptorStringLoader; import com.bumptech.glide.load.model.file_descriptor.FileDescriptorUriLoader; +import com.bumptech.glide.load.model.stream.HttpUrlGlideUrlLoader; import com.bumptech.glide.load.model.stream.StreamFileLoader; import com.bumptech.glide.load.model.stream.StreamModelLoader; import com.bumptech.glide.load.model.stream.StreamResourceLoader; @@ -58,7 +58,6 @@ import com.bumptech.glide.request.Request; import com.bumptech.glide.request.target.ImageViewTargetFactory; import com.bumptech.glide.request.target.Target; import com.bumptech.glide.request.target.ViewTarget; -import com.bumptech.glide.volley.VolleyUrlLoader; import java.io.File; import java.io.InputStream; @@ -81,7 +80,6 @@ public class Glide { private static Glide GLIDE; private final GenericLoaderFactory loaderFactory = new GenericLoaderFactory(); - private final RequestQueue requestQueue; private final Engine engine; private final BitmapPool bitmapPool; private final MemoryCache memoryCache; @@ -170,10 +168,8 @@ public class Glide { GLIDE = null; } - Glide(Engine engine, RequestQueue requestQueue, MemoryCache memoryCache, BitmapPool bitmapPool, - Context context) { + Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context) { this.engine = engine; - this.requestQueue = requestQueue; this.bitmapPool = bitmapPool; this.memoryCache = memoryCache; @@ -201,7 +197,7 @@ public class Glide { register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory()); register(Uri.class, InputStream.class, new StreamUriLoader.Factory()); register(URL.class, InputStream.class, new StreamUrlLoader.Factory()); - register(GlideUrl.class, InputStream.class, new VolleyUrlLoader.Factory(requestQueue)); + register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory()); transcoderFactory.register(Bitmap.class, BitmapDrawable.class, new BitmapDrawableTranscoder(context.getResources(), bitmapPool)); @@ -257,13 +253,6 @@ public class Glide { return loaderFactory; } - /** - * Returns the {@link RequestQueue} Glide is using to fetch images over http/https. - */ - public RequestQueue getRequestQueue() { - return requestQueue; - } - /** * Clears as much memory as possible. * diff --git a/library/src/main/java/com/bumptech/glide/GlideBuilder.java b/library/src/main/java/com/bumptech/glide/GlideBuilder.java index 38c130eb9..b68f8170a 100644 --- a/library/src/main/java/com/bumptech/glide/GlideBuilder.java +++ b/library/src/main/java/com/bumptech/glide/GlideBuilder.java @@ -2,7 +2,6 @@ package com.bumptech.glide; import android.content.Context; import android.os.Build; -import com.android.volley.RequestQueue; import com.bumptech.glide.load.engine.Engine; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPoolAdapter; @@ -14,13 +13,11 @@ import com.bumptech.glide.load.engine.cache.LruResourceCache; import com.bumptech.glide.load.engine.cache.MemoryCache; import com.bumptech.glide.load.engine.cache.MemorySizeCalculator; import com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor; -import com.bumptech.glide.volley.RequestQueueWrapper; import java.io.File; import java.util.concurrent.ExecutorService; public class GlideBuilder { - private RequestQueue requestQueue; private Context context; private Engine engine; private BitmapPool bitmapPool; @@ -33,11 +30,6 @@ public class GlideBuilder { this.context = context.getApplicationContext(); } - public GlideBuilder setRequestQueue(RequestQueue requestQueue) { - this.requestQueue = requestQueue; - return this; - } - public GlideBuilder setBitmapPool(BitmapPool bitmapPool) { this.bitmapPool = bitmapPool; return this; @@ -77,10 +69,6 @@ public class GlideBuilder { diskCacheService = new FifoPriorityThreadPoolExecutor(1); } - if (requestQueue == null) { - requestQueue = RequestQueueWrapper.getRequestQueue(context); - } - MemorySizeCalculator calculator = new MemorySizeCalculator(context); if (bitmapPool == null) { if (Build.VERSION.SDK_INT >= 11) { @@ -108,6 +96,6 @@ public class GlideBuilder { engine = new Engine(memoryCache, diskCache, resizeService, diskCacheService); } - return new Glide(engine, requestQueue, memoryCache, bitmapPool, context); + return new Glide(engine, memoryCache, bitmapPool, context); } } \ No newline at end of file diff --git a/library/src/main/java/com/bumptech/glide/RequestManager.java b/library/src/main/java/com/bumptech/glide/RequestManager.java index 88a8d1f2c..a40dd02a6 100644 --- a/library/src/main/java/com/bumptech/glide/RequestManager.java +++ b/library/src/main/java/com/bumptech/glide/RequestManager.java @@ -8,9 +8,11 @@ import android.os.ParcelFileDescriptor; import android.support.v4.app.FragmentActivity; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; +import com.bumptech.glide.load.data.HttpUrlFetcher; import com.bumptech.glide.load.model.ModelLoader; import com.bumptech.glide.load.model.ModelLoaderFactory; import com.bumptech.glide.load.model.file_descriptor.FileDescriptorModelLoader; +import com.bumptech.glide.load.model.stream.HttpUrlGlideUrlLoader; import com.bumptech.glide.load.model.stream.MediaStoreStreamLoader; import com.bumptech.glide.load.model.stream.StreamByteArrayLoader; import com.bumptech.glide.load.model.stream.StreamFileLoader; @@ -21,7 +23,6 @@ import com.bumptech.glide.load.model.stream.StreamUriLoader; import com.bumptech.glide.manager.ConnectivityMonitor; import com.bumptech.glide.manager.ConnectivityMonitorFactory; import com.bumptech.glide.manager.RequestTracker; -import com.bumptech.glide.volley.VolleyUrlLoader; import java.io.File; import java.io.InputStream; @@ -268,8 +269,7 @@ public class RequestManager { /** * Use the {@link ModelLoaderFactory} currently registered for {@link URL} to load the image represented by the - * given {@link URL}. Defaults to {@link com.bumptech.glide.volley.VolleyUrlLoader.Factory} and - * {@link VolleyUrlLoader} to load the given model. + * given {@link URL}. Defaults to {@link HttpUrlGlideUrlLoader} and {@link HttpUrlFetcher} to load the given model. * * @see #using(StreamModelLoader) * diff --git a/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java b/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java new file mode 100644 index 000000000..ed6f40a62 --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java @@ -0,0 +1,88 @@ +package com.bumptech.glide.load.data; + +import com.bumptech.glide.Priority; +import com.bumptech.glide.load.model.GlideUrl; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +public class HttpUrlFetcher implements DataFetcher { + private static final HttpUrlConnectionFactory DEFAULT_FACTORY = new DefaultHttpUrlConnectionFactory(); + private GlideUrl glideUrl; + private final HttpUrlConnectionFactory factory; + private HttpURLConnection urlConnection; + private boolean isConnected; + private volatile boolean isCancelled; + + public HttpUrlFetcher(GlideUrl glideUrl) { + this(glideUrl, DEFAULT_FACTORY); + } + + HttpUrlFetcher(GlideUrl glideUrl, HttpUrlConnectionFactory factory) { + this.glideUrl = glideUrl; + this.factory = factory; + } + + @Override + public InputStream loadData(Priority priority) throws Exception { + urlConnection = factory.build(glideUrl.toURL()); + urlConnection.setConnectTimeout(2500); + urlConnection.setReadTimeout(2500); + urlConnection.setUseCaches(false); + urlConnection.setDoInput(true); + + // Connect explicitly to avoid errors in decoders if connection fails. + urlConnection.connect(); + synchronized (this) { + isConnected = true; + } + if (isCancelled) { + return null; + } + final int statusCode = urlConnection.getResponseCode(); + if (statusCode / 100 == 2) { + return urlConnection.getInputStream(); + } else { + if (statusCode == -1) { + throw new IOException("Unable to retrieve response code from HttpUrlConnection."); + } + throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage()); + } + } + + @Override + public void cleanup() { + if (urlConnection != null) { + urlConnection.disconnect(); + } + } + + @Override + public String getId() { + return glideUrl.toString(); + } + + @Override + public void cancel() { + synchronized (this) { + if (!isConnected && urlConnection != null) { + urlConnection.disconnect(); + } + } + isCancelled = true; + } + + interface HttpUrlConnectionFactory { + public HttpURLConnection build(URL url) throws IOException; + } + + private static class DefaultHttpUrlConnectionFactory implements HttpUrlConnectionFactory { + @Override + public HttpURLConnection build(URL url) throws IOException { + return (HttpURLConnection) url.openConnection(); + } + } + +} diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoader.java new file mode 100644 index 000000000..ef3bfd63c --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoader.java @@ -0,0 +1,31 @@ +package com.bumptech.glide.load.model.stream; + +import android.content.Context; +import com.bumptech.glide.load.data.DataFetcher; +import com.bumptech.glide.load.data.HttpUrlFetcher; +import com.bumptech.glide.load.model.GenericLoaderFactory; +import com.bumptech.glide.load.model.GlideUrl; +import com.bumptech.glide.load.model.ModelLoader; +import com.bumptech.glide.load.model.ModelLoaderFactory; + +import java.io.InputStream; + +public class HttpUrlGlideUrlLoader implements ModelLoader { + + public static class Factory implements ModelLoaderFactory { + @Override + public ModelLoader build(Context context, GenericLoaderFactory factories) { + return new HttpUrlGlideUrlLoader(); + } + + @Override + public void teardown() { + + } + } + + @Override + public DataFetcher getResourceFetcher(GlideUrl model, int width, int height) { + return new HttpUrlFetcher(model); + } +} diff --git a/library/src/test/java/com/bumptech/glide/GlideTest.java b/library/src/test/java/com/bumptech/glide/GlideTest.java index 16d6f5daf..bfc8ebcf6 100644 --- a/library/src/test/java/com/bumptech/glide/GlideTest.java +++ b/library/src/test/java/com/bumptech/glide/GlideTest.java @@ -13,10 +13,6 @@ import android.os.Handler; import android.os.ParcelFileDescriptor; import android.view.ViewGroup; import android.widget.ImageView; -import com.android.volley.Network; -import com.android.volley.NetworkResponse; -import com.android.volley.RequestQueue; -import com.android.volley.toolbox.NoCache; import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; @@ -39,8 +35,6 @@ import com.bumptech.glide.request.Request; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.Target; import com.bumptech.glide.tests.GlideShadowLooper; -import com.bumptech.glide.volley.VolleyRequestFuture; -import com.bumptech.glide.volley.VolleyUrlLoader; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -62,12 +56,10 @@ import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.UUID; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyObject; @@ -118,45 +110,21 @@ public class GlideTest { } }); - // Make sure Volley does not actually perform any network requests. - Network network = mock(Network.class); - when(network.performRequest(any(com.android.volley.Request.class))) - .thenAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - return new NetworkResponse(new byte[0]); - } - }); - - RequestQueue requestQueue = new RequestQueue(new NoCache(), network); - requestQueue.start(); Glide.setup(new GlideBuilder(Robolectric.application) .setMemoryCache(mock(MemoryCache.class)) .setDiskCache(mock(DiskCache.class)) .setResizeService(service) - .setDiskCacheService(service) - .setRequestQueue(requestQueue)); - - // Sleep to avoid blocking the main thread while waiting for Volley's background thread to complete - // and for the result to be posted back to the main thread. - VolleyUrlLoader.FutureFactory futureFactory = mock(VolleyUrlLoader.FutureFactory.class); - VolleyRequestFuture future = new VolleyRequestFuture() { - @Override - public InputStream get() throws InterruptedException, ExecutionException { - for (int i = 0; i < 10 && !isDone(); i++) { - Thread.sleep(10); - // Make sure the result callback posted on the main thread actually runs. - Robolectric.runUiThreadTasks(); - } - if (!isDone()) { - fail("Failed to get response from Volley in time"); - } - return super.get(); - } - }; - when(futureFactory.build()).thenReturn(future); - Glide.get(getContext()).register(GlideUrl.class, InputStream.class, - new VolleyUrlLoader.Factory(Glide.get(getContext()).getRequestQueue(), futureFactory)); + .setDiskCacheService(service)); + DataFetcher mockStreamFetcher = mock(DataFetcher.class); + when(mockStreamFetcher.getId()).thenReturn("fakeId"); + when(mockStreamFetcher.loadData(any(Priority.class))).thenReturn(new ByteArrayInputStream(new byte[0])); + ModelLoader mockUrlLoader = mock(ModelLoader.class); + when(mockUrlLoader.getResourceFetcher(any(GlideUrl.class), anyInt(), anyInt())).thenReturn(mockStreamFetcher); + ModelLoaderFactory mockUrlLoaderFactory = mock(ModelLoaderFactory.class); + when(mockUrlLoaderFactory.build(any(Context.class), any(GenericLoaderFactory.class))) + .thenReturn(mockUrlLoader); + + Glide.get(getContext()).register(GlideUrl.class, InputStream.class, mockUrlLoaderFactory); } @After diff --git a/library/src/test/java/com/bumptech/glide/load/data/HttpUrlFetcherTest.java b/library/src/test/java/com/bumptech/glide/load/data/HttpUrlFetcherTest.java new file mode 100644 index 000000000..207fda9b7 --- /dev/null +++ b/library/src/test/java/com/bumptech/glide/load/data/HttpUrlFetcherTest.java @@ -0,0 +1,158 @@ +package com.bumptech.glide.load.data; + +import com.bumptech.glide.Priority; +import com.bumptech.glide.load.model.GlideUrl; +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.concurrent.CountDownLatch; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class HttpUrlFetcherTest { + private HttpURLConnection urlConnection; + private HttpUrlFetcher fetcher; + private GlideUrl glideUrl; + + @Before + public void setUp() throws IOException { + urlConnection = mock(HttpURLConnection.class); + URL url = new URL("http://www.google.com"); + HttpUrlFetcher.HttpUrlConnectionFactory factory = mock(HttpUrlFetcher.HttpUrlConnectionFactory.class); + when(factory.build(eq(url))).thenReturn(urlConnection); + glideUrl = mock(GlideUrl.class); + when(glideUrl.toURL()).thenReturn(url); + fetcher = new HttpUrlFetcher(glideUrl, factory); + when(urlConnection.getResponseCode()).thenReturn(200); + } + + @Test + public void testReturnsModelAsString() { + final String expected = "fakeId"; + when(glideUrl.toString()).thenReturn(expected); + assertEquals(expected, fetcher.getId()); + } + + + @Test + public void testSetsReadTimeout() throws Exception { + fetcher.loadData(Priority.HIGH); + verify(urlConnection).setReadTimeout(eq(2500)); + } + + @Test + public void testSetsConnectTimeout() throws Exception { + fetcher.loadData(Priority.IMMEDIATE); + verify(urlConnection).setConnectTimeout(eq(2500)); + } + + @Test + public void testReturnsInputStreamOnStatusOk() throws Exception { + InputStream expected = new ByteArrayInputStream(new byte[0]); + when(urlConnection.getResponseCode()).thenReturn(200); + when(urlConnection.getInputStream()).thenReturn(expected); + + assertEquals(expected, fetcher.loadData(Priority.NORMAL)); + } + + @Test(expected = IOException.class) + public void testThrowsIfStatusCodeIsNegativeOne() throws Exception { + when(urlConnection.getResponseCode()).thenReturn(-1); + fetcher.loadData(Priority.HIGH); + } + + @Test(expected = IOException.class) + public void testThrowsIfStatusCodeIs300() throws Exception { + when(urlConnection.getResponseCode()).thenReturn(300); + fetcher.loadData(Priority.HIGH); + } + + @Test(expected = IOException.class) + public void testThrowsIfStatusCodeIs500() throws Exception { + when(urlConnection.getResponseCode()).thenReturn(500); + fetcher.loadData(Priority.HIGH); + } + + @Test + public void testReturnsNullIfCancelledBeforeConnects() throws Exception { + InputStream notExpected = new ByteArrayInputStream(new byte[0]); + when(urlConnection.getInputStream()).thenReturn(notExpected); + + fetcher.cancel(); + assertNull(fetcher.loadData(Priority.LOW)); + } + + @Test + public void testDisconnectsUrlOnCleanup() throws Exception { + fetcher.loadData(Priority.HIGH); + fetcher.cleanup(); + + verify(urlConnection).disconnect(); + } + + @Test + public void testDoesNotThrowIfCleanupCalledBeforeStarted() { + fetcher.cleanup(); + } + + @Test + public void testDoesNotThrowIfCancelCalledBeforeStart() { + fetcher.cancel(); + } + + @Test + public void testCancelDoesNotDisconnectIfAlreadyConnected() throws Exception { + fetcher.loadData(Priority.HIGH); + fetcher.cancel(); + + verify(urlConnection, never()).disconnect(); + } + + @Test + public void testDisconnectsUrlConnectionOnCancelIfNotYetCancelled() throws IOException, InterruptedException { + final CountDownLatch mainThreadLatch = new CountDownLatch(1); + final CountDownLatch countDownLatch = new CountDownLatch(1); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + mainThreadLatch.countDown(); + countDownLatch.await(); + return null; + } + }).when(urlConnection).connect(); + + Thread bg = new Thread() { + @Override + public void run() { + try { + fetcher.loadData(Priority.HIGH); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + bg.start(); + + mainThreadLatch.await(); + fetcher.cancel(); + countDownLatch.countDown(); + bg.join(); + + verify(urlConnection).connect(); + verify(urlConnection).disconnect(); + } +} \ No newline at end of file diff --git a/library/src/test/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoaderTest.java b/library/src/test/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoaderTest.java new file mode 100644 index 000000000..640ba0b78 --- /dev/null +++ b/library/src/test/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoaderTest.java @@ -0,0 +1,29 @@ +package com.bumptech.glide.load.model.stream; + +import com.bumptech.glide.load.data.DataFetcher; +import com.bumptech.glide.load.data.HttpUrlFetcher; +import com.bumptech.glide.load.model.GlideUrl; +import org.junit.Before; +import org.junit.Test; + +import java.io.InputStream; + +import static junit.framework.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +public class HttpUrlGlideUrlLoaderTest { + private HttpUrlGlideUrlLoader loader; + private GlideUrl model; + + @SuppressWarnings("unchecked") + @Before + public void setUp() { + loader = new HttpUrlGlideUrlLoader(); + model = mock(GlideUrl.class); + } + @Test + public void testReturnsValidFetcher() { + DataFetcher result = loader.getResourceFetcher(model, 100, 100); + assertTrue(result instanceof HttpUrlFetcher); + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index eee940504..94cb5d018 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ library third_party + integration samples @@ -33,11 +34,6 @@ 4.4.2_r3 provided - - com.mcxiaoke.volley - library - 1.0.4 - diff --git a/samples/flickr/pom.xml b/samples/flickr/pom.xml index b61db0803..e3f6620e0 100644 --- a/samples/flickr/pom.xml +++ b/samples/flickr/pom.xml @@ -16,10 +16,9 @@ com.github.bumptech.glide - glide + library 3.3.0-SNAPSHOT aar - compile com.actionbarsherlock @@ -33,5 +32,10 @@ + + com.mcxiaoke.volley + library + 1.0.4 + diff --git a/samples/flickr/src/main/java/com/bumptech/glide/samples/flickr/FlickrSearchActivity.java b/samples/flickr/src/main/java/com/bumptech/glide/samples/flickr/FlickrSearchActivity.java index d8062a2a3..5ff521ba1 100644 --- a/samples/flickr/src/main/java/com/bumptech/glide/samples/flickr/FlickrSearchActivity.java +++ b/samples/flickr/src/main/java/com/bumptech/glide/samples/flickr/FlickrSearchActivity.java @@ -1,5 +1,6 @@ package com.bumptech.glide.samples.flickr; +import android.annotation.TargetApi; import android.os.Bundle; import android.os.StrictMode; import android.support.v4.app.Fragment; @@ -70,6 +71,7 @@ public class FlickrSearchActivity extends SherlockFragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + Glide.get(this).register(Photo.class, InputStream.class, new FlickrModelLoader.Factory()); setContentView(R.layout.flickr_search_activity); @@ -127,7 +129,7 @@ public class FlickrSearchActivity extends SherlockFragmentActivity { pager.setAdapter(new FlickrPagerAdapter(getSupportFragmentManager())); - Api.get(Glide.get(this).getRequestQueue()).registerSearchListener(searchListener); + Api.get(this).registerSearchListener(searchListener); if (savedInstanceState != null) { String savedSearchString = savedInstanceState.getString(STATE_SEARCH_STRING); if (!TextUtils.isEmpty(savedSearchString)) { @@ -147,9 +149,10 @@ public class FlickrSearchActivity extends SherlockFragmentActivity { @Override protected void onDestroy() { super.onDestroy(); - Api.get(Glide.get(this).getRequestQueue()).unregisterSearchListener(searchListener); + Api.get(this).unregisterSearchListener(searchListener); } + @TargetApi(14) @Override public void onTrimMemory(int level) { super.onTrimMemory(level); @@ -179,7 +182,7 @@ public class FlickrSearchActivity extends SherlockFragmentActivity { searchLoading.setVisibility(View.VISIBLE); searchTerm.setText(getString(R.string.searching_for, currentSearchString)); - Api.get(Glide.get(this).getRequestQueue()).search(currentSearchString); + Api.get(this).search(currentSearchString); } private static class TabListener implements ActionBar.TabListener { diff --git a/samples/flickr/src/main/java/com/bumptech/glide/samples/flickr/api/Api.java b/samples/flickr/src/main/java/com/bumptech/glide/samples/flickr/api/Api.java index 995fd7e2b..91be8eba1 100644 --- a/samples/flickr/src/main/java/com/bumptech/glide/samples/flickr/api/Api.java +++ b/samples/flickr/src/main/java/com/bumptech/glide/samples/flickr/api/Api.java @@ -1,5 +1,6 @@ package com.bumptech.glide.samples.flickr.api; +import android.content.Context; import android.text.TextUtils; import android.util.Log; import com.android.volley.DefaultRetryPolicy; @@ -8,6 +9,7 @@ import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; +import com.android.volley.toolbox.Volley; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -85,9 +87,9 @@ public class Api { public void onSearchFailed(String searchString, Exception e); } - public static Api get(RequestQueue requestQueue) { + public static Api get(Context context) { if (API == null) { - API = new Api(requestQueue); + API = new Api(context); } return API; } @@ -96,8 +98,8 @@ public class Api { private final Set searchListeners = new HashSet(); private SearchResult lastSearchResult; - protected Api(RequestQueue requestQueue) { - this.requestQueue = requestQueue; + protected Api(Context context) { + this.requestQueue = Volley.newRequestQueue(context.getApplicationContext()); } public void registerSearchListener(SearchListener searchListener) { diff --git a/settings.gradle b/settings.gradle index e926c9161..1a1e7c39a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ include ':library' include ':third_party:gif_decoder' -include ':samples:flickr' \ No newline at end of file +include ':samples:flickr' +include ':integration:volley' \ No newline at end of file -- GitLab