diff options
author | Anonymous <no-reply@google.com> | 2018-05-11 11:23:20 -0700 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2018-05-11 11:23:20 -0700 |
commit | b2a5b6d7a27822b0ed8486485d1cd0e16b01df9d (patch) | |
tree | f39fa51c442a9c6922d1f6def2e75d5dca677f20 | |
parent | c3a0e7848f09ade3a05d9d23a52d1cf21373a841 (diff) | |
parent | f6db66b103746d0ff38a29ad492a9a20cd5e24fe (diff) | |
download | volley-b2a5b6d7a27822b0ed8486485d1cd0e16b01df9d.tar.gz |
Import of Volley from GitHub to AOSP. am: 9a12854004 am: 98a64fa3fc
am: f6db66b103
Change-Id: I51e3fd00fa31221a5ad6cdc39abd41245652711c
92 files changed, 2181 insertions, 2140 deletions
diff --git a/.travis.yml b/.travis.yml index 4c80cfd..44ff763 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,9 +28,9 @@ cache: env: global: - - secure: pQb1CpD3heCma1831L4rnZGHgn6acFoBMlRrMBWc7nXXM5WwQ4cMSwZ49TVGMMVobA76vKm6dZj4n5ut5/i9amS9Ohlxbpjw5jVp1dqgev6PMupimkYfeTjTVdfGDlian8J7g4kQcVBXghq2WR+rUVh+VlhenE7r7lzEAscWRAKmo0Dzv1E3idI9ik8gkcAdE0ICJmYoq7vxxBhI3XzofHdq0bkzaCzU4P4OSX5HFN8Z4EloTeEeKZj0f02NwS+rrYzhNDs+8619W1gffAjJ9+C0im7iU8axoxMDE9e5dO4PEO03ol/U7F1NNmwFJ+Q78f9qmNw8u4EYnfzUn7nkH+GvYvX9jGlJoNqXPet0eKsJVIShx5eZjpgtUO0ICZKxYuqtKVfj55MPicMLhKFr1VvUTI4noomQVraUAtnI/H0Ia28795WLry4lbMRuYAwCpsmKJKKNQ5sj3dkokpMmn7SH64zNIxKHpAEkrg3UUWh0LUvk7ePn45RAPXS5M0EX0z6LvQEi5dRVfSc2b69CX9vXyqoG/29xwdaYV+BSZjc1zDFN9BXAwDWhfs86ONSmovi5SXoKd/7FWoEAQVX/ZAW93HuScq5pMq7RYbjN4IThqhCC/K6TgwC2PRtPaIK/Rucc9Gvs8Gh5nphabSDzIPoGUEXXPG+lsG10G9qxGKU= - - secure: NhFfhYu6WNuFNpJt3GoGMYpWdYv3xfS7FExeEidvIol+GbuglCv/FOVYVFdHnE52+lvmLz1UTdOSvMhbQe6mhL+ZJQYCILH5i3ion92MlH6YWaJisafzBvSrhUjMFzo0LEJwJ9k3FsAARc0QR+GIsyd0un4MrybeZwFX0VzLElxRl5bEXnxXqYjdw7Mzs3fyROnxees1waz6Ksu3v8NPk45ooy633DGl3txVI/05rT89WwtUnvz0ieAAMiOUTOWs6lAkb45hAzdBng+U5YNL/BiK1y+o4PFYCF7nNJ2A2s6qG/hZYiTa3tLR2tgb5sDHQl4KZ2YEVdEGCZ52nY5vNXAWWZIp1thJYOmaVXFHn/YG8+Qpr2+maUHjzlttIOWl41JSN54emyrK5ZbbAKzMOYKZeRcDP41oP9YlqnsPSL2GBbxqG2GAzv5btHXQPTJVpbqwZUOjYM6jetzRifIWisreN8qQ3cWXLe5l/ra0E6TUbOBH2fC0tZwYe6tkmSGnskA81KwmX7qqKdeJvlAYbGS6MylOSlMmrYqmpKCpofatT1/ZYrnZZSPNRZGQt0L+D1LaYMYlEkSqboxb/OCBL+oD6ncsJWT2YYTQSPdqfmUHF8pNi3hCJe04pqVCbaoEYyMrPlZ+PeZnYDuNSC+Moyu+z7Cqikqg2flzH+F0Az0= + - secure: "ObTSgg1H/RoQwhf9735Cr0OEs7r296aQTKiVOmQYSIxZPzc7o2KveSVV8IVeQ+VQtDxPFij6Odk4gaQSKVytliTlgtSsrEaYt67yWWYLWBLWbnzLNYoWMMy+36O5BK78RNtVJ3Xr1mdMcZ2+SRj2TcEvQBqMWlUkJfEcmJttreq0Wd7jiNitv5MbyYRcd2AvKaqNilx5rEm1ihbE0wT3lH20EdAjjjckaBT04r+VXU9e0dg6tmZjqG8dxGzxYHLRTz7nmKXlUnOJ3steNPrmR/AsGqKW6Ppowi31t3iLpL3zdT0+mvzfvnQwBodqHWSU/JhVDGlePv+4a5aU80s+5nN1IKL7tTLGYWoKdoIuQLovRkdcdkuj8UNyftPj6qOO2C9Tk8j64WXwUIDRnmNfjXbFzqN51oiT94G6hPcEDQSxLwuqlmgNm9I9WxZidb5YotIN2BcIKthAvdL4ecxE5INJvss8DVdYUZ53000GqSoMv8WET6jYkSJPKfvmTgpqqYIW0sgMiDfO/ta/MTFG5kSqECL+sAFZNmugwmTc7NIdy29myCyLH/A6oM4n3QeFDDHhOl2cRYlsX3juzw2goRppR9sEosFN0D1T7Fije5RmJsPgVLGwYMxSGukAHufcatKfhccUVl+haSJ3PLQ1z+25Ug2kpJwMAHbUYWCBnew=" + - secure: "Ac95rbJd5dgNdK8ZlaeXpkKYXHGNj8pm4eNv1Oe8YtsByshHtBAK1m55H4Ex55oRXaLXntvQwnnJfqeTDPuqvd7QP1fjvp4Yjdaqa8MkC6qdVtm6LaqsGuE38uSiU6oxJKfnlCywNe2LfFlbzBtPd3ejNI7tfJcO3s1mD2aBT46vmwUy0t5ESxNdP2zUs6DFcbaOUWeJhQn8iNdRm2VbHEMdevzvvXXIUB9YUdBZQIuAZ5E8NRP5/dzPE8P0CY6/yXqQ/6bkXRV3Pf9QsRzJ+oEQVJAIFfC4JAGasgaBIVpaJ2C2At39jrNFpGYUNbHxvkBEal+WiaPk5TfmVbpyWJOTPRaaY3tIRdBbYf6kklnQk2jRJB6GCi4/yvT6oNjTQQEwsuYlaivkibwNehQqtqyjj12CcTI7lwbgNXeLvIWE6LNLIxrY4pnNy3bKjA0oLFoG/FuP3Wi9WldBtVXwvUBVFFXeOgzP6lCDkzGYTwYZi20lRmSgma3Q5e3/BbPtos3BZ9dSY3lUjttGxvHEDCJ48U1aw6usR91ZKD78Thb5OxWLkvs4rjWEDU2I649wiYSyqFldNEnv+2SJSRB+097XEcnCopGXorlMhBMAlhwHyiRY1u0D+9qrpfIl9Z07j0ZiG5uIscDXQZZjMivqe/+u8NJ3kN0zrDO5BQEgNls=" # Publish a SNAPSHOT build for all commits to master. -after_success: - - ./publish-snapshot-on-commit.sh
\ No newline at end of file +script: + - ./gradlew --continue verifyGoogleJavaFormat build connectedCheck && ./publish-snapshot-on-commit.sh @@ -22,11 +22,10 @@ LOCAL_MODULE := volley LOCAL_SDK_VERSION := 17 LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java) -include $(BUILD_STATIC_JAVA_LIBRARY) +# Only needed at compile-time. +LOCAL_JAVA_LIBRARIES := android-support-annotations -# Include this library in the build server's output directory -# TODO: Not yet. -#$(call dist-for-goals, dist_files, $(LOCAL_BUILT_MODULE):volley.jar) +include $(BUILD_STATIC_JAVA_LIBRARY) # Include build files in subdirectories include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 79d185a..09691bd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,3 +23,19 @@ use GitHub pull requests for this purpose. Consult [GitHub Help] for more information on using pull requests. [GitHub Help]: https://help.github.com/articles/about-pull-requests/ + +## Preparing a pull request for review + +Ensure your change is properly formatted by running: + +```console +$ ./gradlew googleJavaFormat +``` + +Then verify that your change builds and passes tests with: + +```console +$ ./gradlew --continue verifyGoogleJavaFormat build connectedCheck +``` + +Please correct any failures before requesting a review. diff --git a/bintray-info-template.json b/bintray-info-template.json deleted file mode 100644 index 4021964..0000000 --- a/bintray-info-template.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "package": { - "user_org": "android", - "repo": "android-utils", - "group": "com.android.volley", - "name": "com.android.volley.volley", - "desc": "Volley Android library", - "licenses": ["Apache-2.0"], - "website_url": "https://github.com/google/volley", - "issue_tracker_url": "https://github.com/google/volley/issues", - "vcs_url": "https://github.com/google/volley.git", - "labels": ["android", "volley", "network"], - "public_download_numbers": true - }, - "version": { - "name": "$VERSION$", - "desc": "Volley Android library version $VERSION$", - "gpgSign": false - }, - "publish": true -}
\ No newline at end of file diff --git a/bintray.gradle b/bintray.gradle index d7b23d0..05700a4 100644 --- a/bintray.gradle +++ b/bintray.gradle @@ -15,10 +15,6 @@ buildscript { apply plugin: org.jfrog.gradle.plugin.artifactory.ArtifactoryPlugin apply plugin: 'maven-publish' -def bintrayInfoFilePath = "$buildDir/outputs/bintray-descriptor.bintray-info.json" - -project.ext.version = '1.1.0-SNAPSHOT' - task sourcesJar(type: Jar) { classifier = 'sources' from android.sourceSets.main.java.srcDirs @@ -34,16 +30,6 @@ task javadocJar(type: Jar, dependsOn: javadoc) { from javadoc.destinationDir } -task bintrayInfoFile { - outputs.file(bintrayInfoFilePath) - doLast { - println 'Creating bintray-info.json' - String fileContent = new File("$rootDir/bintray-info-template.json").getText('UTF-8') - fileContent = fileContent.replace('$VERSION$', project.ext.version) - ((new File(bintrayInfoFilePath))).write(fileContent) - } -} - artifacts { archives javadocJar archives sourcesJar @@ -54,7 +40,7 @@ publishing { library(MavenPublication) { groupId 'com.android.volley' artifactId 'volley' - version project.ext.version + version project.version pom { packaging 'aar' } @@ -63,10 +49,6 @@ publishing { artifact "$buildDir/outputs/aar/volley-release.aar" artifact sourcesJar artifact javadocJar - artifact(bintrayInfoFilePath) { - builtBy bintrayInfoFile - extension "bintray-info.json" - } } } } diff --git a/build.gradle b/build.gradle index f4ca9fa..537b55b 100644 --- a/build.gradle +++ b/build.gradle @@ -23,16 +23,37 @@ buildscript { } } +plugins { + id "com.github.sherter.google-java-format" version "0.6" + id "net.ltgt.errorprone" version "0.0.13" +} + +googleJavaFormat { + toolVersion = '1.5' + options style: 'AOSP' +} + apply plugin: 'com.android.library' repositories { jcenter() + maven { + url 'https://maven.google.com/' + name 'Google' + } } +group = 'com.android.volley' +version = '1.1.1-SNAPSHOT' + android { compileSdkVersion 25 buildToolsVersion = '25.0.2' } +tasks.withType(JavaCompile) { + options.compilerArgs << "-Xep:ParameterComment:ERROR" +} + apply from: 'rules.gradle' apply from: 'bintray.gradle' diff --git a/rules.gradle b/rules.gradle index 21df898..49aa24b 100644 --- a/rules.gradle +++ b/rules.gradle @@ -15,6 +15,14 @@ android { } } +tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:unchecked" << "-Werror" +} + +dependencies { + provided "com.android.support:support-annotations:27.1.1" +} + // Check if the android plugin version supports unit testing. if (configurations.findByName("testCompile")) { dependencies { diff --git a/src/main/java/com/android/volley/AuthFailureError.java b/src/main/java/com/android/volley/AuthFailureError.java index 87c811d..fc6417e 100644 --- a/src/main/java/com/android/volley/AuthFailureError.java +++ b/src/main/java/com/android/volley/AuthFailureError.java @@ -18,15 +18,13 @@ package com.android.volley; import android.content.Intent; -/** - * Error indicating that there was an authentication failure when performing a Request. - */ +/** Error indicating that there was an authentication failure when performing a Request. */ @SuppressWarnings("serial") public class AuthFailureError extends VolleyError { /** An intent that can be used to resolve this exception. (Brings up the password dialog.) */ private Intent mResolutionIntent; - public AuthFailureError() { } + public AuthFailureError() {} public AuthFailureError(Intent intent) { mResolutionIntent = intent; diff --git a/src/main/java/com/android/volley/Cache.java b/src/main/java/com/android/volley/Cache.java index fd7eea1..35b2a96 100644 --- a/src/main/java/com/android/volley/Cache.java +++ b/src/main/java/com/android/volley/Cache.java @@ -20,12 +20,11 @@ import java.util.Collections; import java.util.List; import java.util.Map; -/** - * An interface for a cache keyed by a String with a byte array as data. - */ +/** An interface for a cache keyed by a String with a byte array as data. */ public interface Cache { /** * Retrieves an entry from the cache. + * * @param key Cache key * @return An {@link Entry} or null in the event of a cache miss */ @@ -33,19 +32,21 @@ public interface Cache { /** * Adds or replaces an entry to the cache. + * * @param key Cache key * @param entry Data to store and metadata for cache coherency, TTL, etc. */ void put(String key, Entry entry); /** - * Performs any potentially long-running actions needed to initialize the cache; - * will be called from a worker thread. + * Performs any potentially long-running actions needed to initialize the cache; will be called + * from a worker thread. */ void initialize(); /** * Invalidates an entry in the cache. + * * @param key Cache key * @param fullExpire True to fully expire the entry, false to soft expire */ @@ -53,18 +54,15 @@ public interface Cache { /** * Removes an entry from the cache. + * * @param key Cache key */ void remove(String key); - /** - * Empties the cache. - */ + /** Empties the cache. */ void clear(); - /** - * Data and metadata for an entry returned by the cache. - */ + /** Data and metadata for an entry returned by the cache. */ class Entry { /** The data returned from cache. */ public byte[] data; @@ -110,5 +108,4 @@ public interface Cache { return this.softTtl < System.currentTimeMillis(); } } - } diff --git a/src/main/java/com/android/volley/CacheDispatcher.java b/src/main/java/com/android/volley/CacheDispatcher.java index cd3635d..4ea8a0b 100644 --- a/src/main/java/com/android/volley/CacheDispatcher.java +++ b/src/main/java/com/android/volley/CacheDispatcher.java @@ -17,7 +17,7 @@ package com.android.volley; import android.os.Process; - +import android.support.annotation.VisibleForTesting; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -27,11 +27,10 @@ import java.util.concurrent.BlockingQueue; /** * Provides a thread for performing cache triage on a queue of requests. * - * Requests added to the specified cache queue are resolved from cache. - * Any deliverable response is posted back to the caller via a - * {@link ResponseDelivery}. Cache misses and responses that require - * refresh are enqueued on the specified network queue for processing - * by a {@link NetworkDispatcher}. + * <p>Requests added to the specified cache queue are resolved from cache. Any deliverable response + * is posted back to the caller via a {@link ResponseDelivery}. Cache misses and responses that + * require refresh are enqueued on the specified network queue for processing by a {@link + * NetworkDispatcher}. */ public class CacheDispatcher extends Thread { @@ -56,8 +55,8 @@ public class CacheDispatcher extends Thread { private final WaitingRequestManager mWaitingRequestManager; /** - * Creates a new cache triage dispatcher thread. You must call {@link #start()} - * in order to begin processing. + * Creates a new cache triage dispatcher thread. You must call {@link #start()} in order to + * begin processing. * * @param cacheQueue Queue of incoming requests for triage * @param networkQueue Queue to post requests that require network to @@ -65,8 +64,10 @@ public class CacheDispatcher extends Thread { * @param delivery Delivery interface to use for posting responses */ public CacheDispatcher( - BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue, - Cache cache, ResponseDelivery delivery) { + BlockingQueue<Request<?>> cacheQueue, + BlockingQueue<Request<?>> networkQueue, + Cache cache, + ResponseDelivery delivery) { mCacheQueue = cacheQueue; mNetworkQueue = networkQueue; mCache = cache; @@ -75,8 +76,8 @@ public class CacheDispatcher extends Thread { } /** - * Forces this dispatcher to quit immediately. If any requests are still in - * the queue, they are not guaranteed to be processed. + * Forces this dispatcher to quit immediately. If any requests are still in the queue, they are + * not guaranteed to be processed. */ public void quit() { mQuit = true; @@ -111,6 +112,11 @@ public class CacheDispatcher extends Thread { // Get a request from the cache triage queue, blocking until // at least one is available. final Request<?> request = mCacheQueue.take(); + processRequest(request); + } + + @VisibleForTesting + void processRequest(final Request<?> request) throws InterruptedException { request.addMarker("cache-queue-take"); // If the request has been canceled, don't bother dispatching it. @@ -142,8 +148,9 @@ public class CacheDispatcher extends Thread { // We have a cache hit; parse its data for delivery back to the request. request.addMarker("cache-hit"); - Response<?> response = request.parseNetworkResponse( - new NetworkResponse(entry.data, entry.responseHeaders)); + Response<?> response = + request.parseNetworkResponse( + new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); if (!entry.refreshNeeded()) { @@ -161,17 +168,20 @@ public class CacheDispatcher extends Thread { if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) { // Post the intermediate response back to the user and have // the delivery then forward the request along to the network. - mDelivery.postResponse(request, response, new Runnable() { - @Override - public void run() { - try { - mNetworkQueue.put(request); - } catch (InterruptedException e) { - // Restore the interrupted status - Thread.currentThread().interrupt(); - } - } - }); + mDelivery.postResponse( + request, + response, + new Runnable() { + @Override + public void run() { + try { + mNetworkQueue.put(request); + } catch (InterruptedException e) { + // Restore the interrupted status + Thread.currentThread().interrupt(); + } + } + }); } else { // request has been added to list of waiting requests // to receive the network response from the first request once it returns. @@ -186,10 +196,10 @@ public class CacheDispatcher extends Thread { * Staging area for requests that already have a duplicate request in flight. * * <ul> - * <li>containsKey(cacheKey) indicates that there is a request in flight for the given cache - * key.</li> - * <li>get(cacheKey) returns waiting requests for the given cache key. The in flight request - * is <em>not</em> contained in that list. Is null if no requests are staged.</li> + * <li>containsKey(cacheKey) indicates that there is a request in flight for the given + * cache key. + * <li>get(cacheKey) returns waiting requests for the given cache key. The in flight + * request is <em>not</em> contained in that list. Is null if no requests are staged. * </ul> */ private final Map<String, List<Request<?>>> mWaitingRequests = new HashMap<>(); @@ -214,7 +224,8 @@ public class CacheDispatcher extends Thread { } if (waitingRequests != null) { if (VolleyLog.DEBUG) { - VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.", + VolleyLog.v( + "Releasing %d waiting requests for cacheKey=%s.", waitingRequests.size(), cacheKey); } // Process all queued up requests. @@ -231,7 +242,8 @@ public class CacheDispatcher extends Thread { List<Request<?>> waitingRequests = mWaitingRequests.remove(cacheKey); if (waitingRequests != null && !waitingRequests.isEmpty()) { if (VolleyLog.DEBUG) { - VolleyLog.v("%d waiting requests for cacheKey=%s; resend to network", + VolleyLog.v( + "%d waiting requests for cacheKey=%s; resend to network", waitingRequests.size(), cacheKey); } Request<?> nextInLine = waitingRequests.remove(0); @@ -250,11 +262,12 @@ public class CacheDispatcher extends Thread { } /** - * For cacheable requests, if a request for the same cache key is already in flight, - * add it to a queue to wait for that in-flight request to finish. + * For cacheable requests, if a request for the same cache key is already in flight, add it + * to a queue to wait for that in-flight request to finish. + * * @return whether the request was queued. If false, we should continue issuing the request - * over the network. If true, we should put the request on hold to be processed when - * the in-flight request finishes. + * over the network. If true, we should put the request on hold to be processed when the + * in-flight request finishes. */ private synchronized boolean maybeAddToWaitingRequests(Request<?> request) { String cacheKey = request.getCacheKey(); @@ -264,7 +277,7 @@ public class CacheDispatcher extends Thread { // There is already a request in flight. Queue up. List<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey); if (stagedRequests == null) { - stagedRequests = new ArrayList<Request<?>>(); + stagedRequests = new ArrayList<>(); } request.addMarker("waiting-for-response"); stagedRequests.add(request); diff --git a/src/main/java/com/android/volley/ClientError.java b/src/main/java/com/android/volley/ClientError.java index a8c8141..521b76f 100644 --- a/src/main/java/com/android/volley/ClientError.java +++ b/src/main/java/com/android/volley/ClientError.java @@ -19,8 +19,8 @@ package com.android.volley; /** * Indicates that the server responded with an error response indicating that the client has erred. * - * For backwards compatibility, extends ServerError which used to be thrown for all server errors, - * including 4xx error codes indicating a client error. + * <p>For backwards compatibility, extends ServerError which used to be thrown for all server + * errors, including 4xx error codes indicating a client error. */ @SuppressWarnings("serial") public class ClientError extends ServerError { @@ -32,4 +32,3 @@ public class ClientError extends ServerError { super(); } } - diff --git a/src/main/java/com/android/volley/DefaultRetryPolicy.java b/src/main/java/com/android/volley/DefaultRetryPolicy.java index d8abab0..4be6b50 100644 --- a/src/main/java/com/android/volley/DefaultRetryPolicy.java +++ b/src/main/java/com/android/volley/DefaultRetryPolicy.java @@ -16,9 +16,7 @@ package com.android.volley; -/** - * Default retry policy for requests. - */ +/** Default retry policy for requests. */ public class DefaultRetryPolicy implements RetryPolicy { /** The current timeout in milliseconds. */ private int mCurrentTimeoutMs; @@ -41,15 +39,14 @@ public class DefaultRetryPolicy implements RetryPolicy { /** The default backoff multiplier */ public static final float DEFAULT_BACKOFF_MULT = 1f; - /** - * Constructs a new retry policy using the default timeouts. - */ + /** Constructs a new retry policy using the default timeouts. */ public DefaultRetryPolicy() { this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT); } /** * Constructs a new retry policy. + * * @param initialTimeoutMs The initial timeout for the policy. * @param maxNumRetries The maximum number of retries. * @param backoffMultiplier Backoff multiplier for the policy. @@ -60,45 +57,38 @@ public class DefaultRetryPolicy implements RetryPolicy { mBackoffMultiplier = backoffMultiplier; } - /** - * Returns the current timeout. - */ + /** Returns the current timeout. */ @Override public int getCurrentTimeout() { return mCurrentTimeoutMs; } - /** - * Returns the current retry count. - */ + /** Returns the current retry count. */ @Override public int getCurrentRetryCount() { return mCurrentRetryCount; } - /** - * Returns the backoff multiplier for the policy. - */ + /** Returns the backoff multiplier for the policy. */ public float getBackoffMultiplier() { return mBackoffMultiplier; } /** * Prepares for the next retry by applying a backoff to the timeout. + * * @param error The error code of the last attempt. */ @Override public void retry(VolleyError error) throws VolleyError { mCurrentRetryCount++; - mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier); + mCurrentTimeoutMs += (int) (mCurrentTimeoutMs * mBackoffMultiplier); if (!hasAttemptRemaining()) { throw error; } } - /** - * Returns true if this policy has attempts remaining, false otherwise. - */ + /** Returns true if this policy has attempts remaining, false otherwise. */ protected boolean hasAttemptRemaining() { return mCurrentRetryCount <= mMaxNumRetries; } diff --git a/src/main/java/com/android/volley/ExecutorDelivery.java b/src/main/java/com/android/volley/ExecutorDelivery.java index f36fb75..fd992f9 100644 --- a/src/main/java/com/android/volley/ExecutorDelivery.java +++ b/src/main/java/com/android/volley/ExecutorDelivery.java @@ -17,33 +17,32 @@ package com.android.volley; import android.os.Handler; - import java.util.concurrent.Executor; -/** - * Delivers responses and errors. - */ +/** Delivers responses and errors. */ public class ExecutorDelivery implements ResponseDelivery { /** Used for posting responses, typically to the main thread. */ private final Executor mResponsePoster; /** * Creates a new response delivery interface. + * * @param handler {@link Handler} to post responses on */ public ExecutorDelivery(final Handler handler) { // Make an Executor that just wraps the handler. - mResponsePoster = new Executor() { - @Override - public void execute(Runnable command) { - handler.post(command); - } - }; + mResponsePoster = + new Executor() { + @Override + public void execute(Runnable command) { + handler.post(command); + } + }; } /** - * Creates a new response delivery interface, mockable version - * for testing. + * Creates a new response delivery interface, mockable version for testing. + * * @param executor For running delivery tasks */ public ExecutorDelivery(Executor executor) { @@ -69,12 +68,9 @@ public class ExecutorDelivery implements ResponseDelivery { mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null)); } - /** - * A Runnable used for delivering network responses to a listener on the - * main thread. - */ + /** A Runnable used for delivering network responses to a listener on the main thread. */ @SuppressWarnings("rawtypes") - private class ResponseDeliveryRunnable implements Runnable { + private static class ResponseDeliveryRunnable implements Runnable { private final Request mRequest; private final Response mResponse; private final Runnable mRunnable; @@ -120,6 +116,6 @@ public class ExecutorDelivery implements ResponseDelivery { if (mRunnable != null) { mRunnable.run(); } - } + } } } diff --git a/src/main/java/com/android/volley/Header.java b/src/main/java/com/android/volley/Header.java index ac8aa11..cd9c6ec 100644 --- a/src/main/java/com/android/volley/Header.java +++ b/src/main/java/com/android/volley/Header.java @@ -42,8 +42,7 @@ public final class Header { Header header = (Header) o; - return TextUtils.equals(mName, header.mName) - && TextUtils.equals(mValue, header.mValue); + return TextUtils.equals(mName, header.mName) && TextUtils.equals(mValue, header.mValue); } @Override diff --git a/src/main/java/com/android/volley/Network.java b/src/main/java/com/android/volley/Network.java index 1e367c8..16d5858 100644 --- a/src/main/java/com/android/volley/Network.java +++ b/src/main/java/com/android/volley/Network.java @@ -16,12 +16,11 @@ package com.android.volley; -/** - * An interface for performing requests. - */ +/** An interface for performing requests. */ public interface Network { /** * Performs the specified request. + * * @param request Request to process * @return A {@link NetworkResponse} with data and caching metadata; will never be null * @throws VolleyError on errors diff --git a/src/main/java/com/android/volley/NetworkDispatcher.java b/src/main/java/com/android/volley/NetworkDispatcher.java index 2c04ce0..6e47465 100644 --- a/src/main/java/com/android/volley/NetworkDispatcher.java +++ b/src/main/java/com/android/volley/NetworkDispatcher.java @@ -21,16 +21,16 @@ import android.net.TrafficStats; import android.os.Build; import android.os.Process; import android.os.SystemClock; - +import android.support.annotation.VisibleForTesting; import java.util.concurrent.BlockingQueue; /** * Provides a thread for performing network dispatch from a queue of requests. * - * Requests added to the specified queue are processed from the network via a - * specified {@link Network} interface. Responses are committed to cache, if - * eligible, using a specified {@link Cache} interface. Valid responses and - * errors are posted back to the caller via a {@link ResponseDelivery}. + * <p>Requests added to the specified queue are processed from the network via a specified {@link + * Network} interface. Responses are committed to cache, if eligible, using a specified {@link + * Cache} interface. Valid responses and errors are posted back to the caller via a {@link + * ResponseDelivery}. */ public class NetworkDispatcher extends Thread { @@ -46,16 +46,19 @@ public class NetworkDispatcher extends Thread { private volatile boolean mQuit = false; /** - * Creates a new network dispatcher thread. You must call {@link #start()} - * in order to begin processing. + * Creates a new network dispatcher thread. You must call {@link #start()} in order to begin + * processing. * * @param queue Queue of incoming requests for triage * @param network Network interface to use for performing requests * @param cache Cache interface to use for writing responses to cache * @param delivery Delivery interface to use for posting responses */ - public NetworkDispatcher(BlockingQueue<Request<?>> queue, - Network network, Cache cache, ResponseDelivery delivery) { + public NetworkDispatcher( + BlockingQueue<Request<?>> queue, + Network network, + Cache cache, + ResponseDelivery delivery) { mQueue = queue; mNetwork = network; mCache = cache; @@ -63,8 +66,8 @@ public class NetworkDispatcher extends Thread { } /** - * Forces this dispatcher to quit immediately. If any requests are still in - * the queue, they are not guaranteed to be processed. + * Forces this dispatcher to quit immediately. If any requests are still in the queue, they are + * not guaranteed to be processed. */ public void quit() { mQuit = true; @@ -99,10 +102,14 @@ public class NetworkDispatcher extends Thread { // of time. Update consumer-proguard-rules.pro when modifying this. See also // https://github.com/google/volley/issues/114 private void processRequest() throws InterruptedException { - long startTimeMs = SystemClock.elapsedRealtime(); // Take a request from the queue. Request<?> request = mQueue.take(); + processRequest(request); + } + @VisibleForTesting + void processRequest(Request<?> request) { + long startTimeMs = SystemClock.elapsedRealtime(); try { request.addMarker("network-queue-take"); diff --git a/src/main/java/com/android/volley/NetworkError.java b/src/main/java/com/android/volley/NetworkError.java index 40b41c5..6b2b19f 100644 --- a/src/main/java/com/android/volley/NetworkError.java +++ b/src/main/java/com/android/volley/NetworkError.java @@ -16,9 +16,7 @@ package com.android.volley; -/** - * Indicates that there was a network error when performing a Volley request. - */ +/** Indicates that there was a network error when performing a Volley request. */ @SuppressWarnings("serial") public class NetworkError extends VolleyError { public NetworkError() { diff --git a/src/main/java/com/android/volley/NetworkResponse.java b/src/main/java/com/android/volley/NetworkResponse.java index f0fded3..01f48c6 100644 --- a/src/main/java/com/android/volley/NetworkResponse.java +++ b/src/main/java/com/android/volley/NetworkResponse.java @@ -23,80 +23,106 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; -/** - * Data and headers returned from {@link Network#performRequest(Request)}. - */ +/** Data and headers returned from {@link Network#performRequest(Request)}. */ public class NetworkResponse { /** * Creates a new network response. + * * @param statusCode the HTTP status code * @param data Response body * @param headers Headers returned with this response, or null for none * @param notModified True if the server returned a 304 and the data was already in cache * @param networkTimeMs Round-trip network time to receive network response * @deprecated see {@link #NetworkResponse(int, byte[], boolean, long, List)}. This constructor - * cannot handle server responses containing multiple headers with the same name. - * This constructor may be removed in a future release of Volley. + * cannot handle server responses containing multiple headers with the same name. This + * constructor may be removed in a future release of Volley. */ @Deprecated - public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers, - boolean notModified, long networkTimeMs) { + public NetworkResponse( + int statusCode, + byte[] data, + Map<String, String> headers, + boolean notModified, + long networkTimeMs) { this(statusCode, data, headers, toAllHeaderList(headers), notModified, networkTimeMs); } /** * Creates a new network response. + * * @param statusCode the HTTP status code * @param data Response body * @param notModified True if the server returned a 304 and the data was already in cache * @param networkTimeMs Round-trip network time to receive network response * @param allHeaders All headers returned with this response, or null for none */ - public NetworkResponse(int statusCode, byte[] data, boolean notModified, long networkTimeMs, + public NetworkResponse( + int statusCode, + byte[] data, + boolean notModified, + long networkTimeMs, List<Header> allHeaders) { this(statusCode, data, toHeaderMap(allHeaders), allHeaders, notModified, networkTimeMs); } /** * Creates a new network response. + * * @param statusCode the HTTP status code * @param data Response body * @param headers Headers returned with this response, or null for none * @param notModified True if the server returned a 304 and the data was already in cache * @deprecated see {@link #NetworkResponse(int, byte[], boolean, long, List)}. This constructor - * cannot handle server responses containing multiple headers with the same name. - * This constructor may be removed in a future release of Volley. + * cannot handle server responses containing multiple headers with the same name. This + * constructor may be removed in a future release of Volley. */ @Deprecated - public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers, - boolean notModified) { - this(statusCode, data, headers, notModified, 0); + public NetworkResponse( + int statusCode, byte[] data, Map<String, String> headers, boolean notModified) { + this(statusCode, data, headers, notModified, /* networkTimeMs= */ 0); } /** * Creates a new network response for an OK response with no headers. + * * @param data Response body */ public NetworkResponse(byte[] data) { - this(HttpURLConnection.HTTP_OK, data, false, 0, Collections.<Header>emptyList()); + this( + HttpURLConnection.HTTP_OK, + data, + /* notModified= */ false, + /* networkTimeMs= */ 0, + Collections.<Header>emptyList()); } /** * Creates a new network response for an OK response. + * * @param data Response body * @param headers Headers returned with this response, or null for none * @deprecated see {@link #NetworkResponse(int, byte[], boolean, long, List)}. This constructor - * cannot handle server responses containing multiple headers with the same name. - * This constructor may be removed in a future release of Volley. + * cannot handle server responses containing multiple headers with the same name. This + * constructor may be removed in a future release of Volley. */ @Deprecated public NetworkResponse(byte[] data, Map<String, String> headers) { - this(HttpURLConnection.HTTP_OK, data, headers, false, 0); + this( + HttpURLConnection.HTTP_OK, + data, + headers, + /* notModified= */ false, + /* networkTimeMs= */ 0); } - private NetworkResponse(int statusCode, byte[] data, Map<String, String> headers, - List<Header> allHeaders, boolean notModified, long networkTimeMs) { + private NetworkResponse( + int statusCode, + byte[] data, + Map<String, String> headers, + List<Header> allHeaders, + boolean notModified, + long networkTimeMs) { this.statusCode = statusCode; this.data = data; this.headers = headers; @@ -164,4 +190,3 @@ public class NetworkResponse { return allHeaders; } } - diff --git a/src/main/java/com/android/volley/NoConnectionError.java b/src/main/java/com/android/volley/NoConnectionError.java index fc23156..185eb35 100644 --- a/src/main/java/com/android/volley/NoConnectionError.java +++ b/src/main/java/com/android/volley/NoConnectionError.java @@ -16,9 +16,7 @@ package com.android.volley; -/** - * Error indicating that no connection could be established when performing a Volley request. - */ +/** Error indicating that no connection could be established when performing a Volley request. */ @SuppressWarnings("serial") public class NoConnectionError extends NetworkError { public NoConnectionError() { diff --git a/src/main/java/com/android/volley/ParseError.java b/src/main/java/com/android/volley/ParseError.java index 959d8fb..04a9d58 100644 --- a/src/main/java/com/android/volley/ParseError.java +++ b/src/main/java/com/android/volley/ParseError.java @@ -16,12 +16,10 @@ package com.android.volley; -/** - * Indicates that the server's response could not be parsed. - */ +/** Indicates that the server's response could not be parsed. */ @SuppressWarnings("serial") public class ParseError extends VolleyError { - public ParseError() { } + public ParseError() {} public ParseError(NetworkResponse networkResponse) { super(networkResponse); diff --git a/src/main/java/com/android/volley/Request.java b/src/main/java/com/android/volley/Request.java index 358a327..c958088 100644 --- a/src/main/java/com/android/volley/Request.java +++ b/src/main/java/com/android/volley/Request.java @@ -20,10 +20,10 @@ import android.net.TrafficStats; import android.net.Uri; import android.os.Handler; import android.os.Looper; +import android.support.annotation.CallSuper; +import android.support.annotation.GuardedBy; import android.text.TextUtils; - import com.android.volley.VolleyLog.MarkerLog; - import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Collections; @@ -36,14 +36,10 @@ import java.util.Map; */ public abstract class Request<T> implements Comparable<Request<T>> { - /** - * Default encoding for POST or PUT parameters. See {@link #getParamsEncoding()}. - */ + /** Default encoding for POST or PUT parameters. See {@link #getParamsEncoding()}. */ private static final String DEFAULT_PARAMS_ENCODING = "UTF-8"; - /** - * Supported request methods. - */ + /** Supported request methods. */ public interface Method { int DEPRECATED_GET_OR_POST = -1; int GET = 0; @@ -56,9 +52,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { int PATCH = 7; } - /** - * Callback to notify when the network request returns. - */ + /** Callback to notify when the network request returns. */ /* package */ interface NetworkRequestCompleteListener { /** Callback when a network response has been received. */ @@ -72,7 +66,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { private final MarkerLog mEventLog = MarkerLog.ENABLED ? new MarkerLog() : null; /** - * Request method of this request. Currently supports GET, POST, PUT, DELETE, HEAD, OPTIONS, + * Request method of this request. Currently supports GET, POST, PUT, DELETE, HEAD, OPTIONS, * TRACE, and PATCH. */ private final int mMethod; @@ -87,7 +81,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { private final Object mLock = new Object(); /** Listener interface for errors. */ - // @GuardedBy("mLock") + @GuardedBy("mLock") private Response.ErrorListener mErrorListener; /** Sequence number of this request, used to enforce FIFO ordering. */ @@ -100,11 +94,11 @@ public abstract class Request<T> implements Comparable<Request<T>> { private boolean mShouldCache = true; /** Whether or not this request has been canceled. */ - // @GuardedBy("mLock") + @GuardedBy("mLock") private boolean mCanceled = false; /** Whether or not a response has been delivered for this request yet. */ - // @GuardedBy("mLock") + @GuardedBy("mLock") private boolean mResponseDelivered = false; /** Whether the request should be retried in the event of an HTTP 5xx (server) error. */ @@ -114,9 +108,9 @@ public abstract class Request<T> implements Comparable<Request<T>> { private RetryPolicy mRetryPolicy; /** - * When a request can be retrieved from cache but must be refreshed from - * the network, the cache entry will be stored here so that in the event of - * a "Not Modified" response, we can be sure it hasn't been evicted from cache. + * When a request can be retrieved from cache but must be refreshed from the network, the cache + * entry will be stored here so that in the event of a "Not Modified" response, we can be sure + * it hasn't been evicted from cache. */ private Cache.Entry mCacheEntry = null; @@ -124,14 +118,13 @@ public abstract class Request<T> implements Comparable<Request<T>> { private Object mTag; /** Listener that will be notified when a response has been delivered. */ - // @GuardedBy("mLock") + @GuardedBy("mLock") private NetworkRequestCompleteListener mRequestCompleteListener; /** - * Creates a new request with the given URL and error listener. Note that - * the normal response listener is not provided here as delivery of responses - * is provided by subclasses, who have a better idea of how to deliver an - * already-parsed response. + * Creates a new request with the given URL and error listener. Note that the normal response + * listener is not provided here as delivery of responses is provided by subclasses, who have a + * better idea of how to deliver an already-parsed response. * * @deprecated Use {@link #Request(int, String, com.android.volley.Response.ErrorListener)}. */ @@ -141,10 +134,10 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Creates a new request with the given method (one of the values from {@link Method}), - * URL, and error listener. Note that the normal response listener is not provided here as - * delivery of responses is provided by subclasses, who have a better idea of how to deliver - * an already-parsed response. + * Creates a new request with the given method (one of the values from {@link Method}), URL, and + * error listener. Note that the normal response listener is not provided here as delivery of + * responses is provided by subclasses, who have a better idea of how to deliver an + * already-parsed response. */ public Request(int method, String url, Response.ErrorListener listener) { mMethod = method; @@ -155,16 +148,14 @@ public abstract class Request<T> implements Comparable<Request<T>> { mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url); } - /** - * Return the method for this request. Can be one of the values in {@link Method}. - */ + /** Return the method for this request. Can be one of the values in {@link Method}. */ public int getMethod() { return mMethod; } /** - * Set a tag on this request. Can be used to cancel all requests with this - * tag by {@link RequestQueue#cancelAll(Object)}. + * Set a tag on this request. Can be used to cancel all requests with this tag by {@link + * RequestQueue#cancelAll(Object)}. * * @return This Request object to allow for chaining. */ @@ -175,29 +166,26 @@ public abstract class Request<T> implements Comparable<Request<T>> { /** * Returns this request's tag. + * * @see Request#setTag(Object) */ public Object getTag() { return mTag; } - /** - * @return this request's {@link com.android.volley.Response.ErrorListener}. - */ + /** @return this request's {@link com.android.volley.Response.ErrorListener}. */ public Response.ErrorListener getErrorListener() { - return mErrorListener; + synchronized (mLock) { + return mErrorListener; + } } - /** - * @return A tag for use with {@link TrafficStats#setThreadStatsTag(int)} - */ + /** @return A tag for use with {@link TrafficStats#setThreadStatsTag(int)} */ public int getTrafficStatsTag() { return mDefaultTrafficStatsTag; } - /** - * @return The hashcode of the URL's host component, or 0 if there is none. - */ + /** @return The hashcode of the URL's host component, or 0 if there is none. */ private static int findDefaultTrafficStatsTag(String url) { if (!TextUtils.isEmpty(url)) { Uri uri = Uri.parse(url); @@ -221,9 +209,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { return this; } - /** - * Adds an event to this request's event log; for debugging. - */ + /** Adds an event to this request's event log; for debugging. */ public void addMarker(String tag) { if (MarkerLog.ENABLED) { mEventLog.add(tag, Thread.currentThread().getId()); @@ -233,7 +219,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { /** * Notifies the request queue that this request has finished (successfully or with error). * - * <p>Also dumps all events from this request's event log; for debugging.</p> + * <p>Also dumps all events from this request's event log; for debugging. */ void finish(final String tag) { if (mRequestQueue != null) { @@ -245,13 +231,14 @@ public abstract class Request<T> implements Comparable<Request<T>> { // If we finish marking off of the main thread, we need to // actually do it on the main thread to ensure correct ordering. Handler mainThread = new Handler(Looper.getMainLooper()); - mainThread.post(new Runnable() { - @Override - public void run() { - mEventLog.add(tag, threadId); - mEventLog.finish(this.toString()); - } - }); + mainThread.post( + new Runnable() { + @Override + public void run() { + mEventLog.add(tag, threadId); + mEventLog.finish(Request.this.toString()); + } + }); return; } @@ -272,7 +259,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Sets the sequence number of this request. Used by {@link RequestQueue}. + * Sets the sequence number of this request. Used by {@link RequestQueue}. * * @return This Request object to allow for chaining. */ @@ -281,9 +268,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { return this; } - /** - * Returns the sequence number of this request. - */ + /** Returns the sequence number of this request. */ public final int getSequence() { if (mSequence == null) { throw new IllegalStateException("getSequence called before setSequence"); @@ -291,23 +276,19 @@ public abstract class Request<T> implements Comparable<Request<T>> { return mSequence; } - /** - * Returns the URL of this request. - */ + /** Returns the URL of this request. */ public String getUrl() { return mUrl; } - /** - * Returns the cache key for this request. By default, this is the URL. - */ + /** Returns the cache key for this request. By default, this is the URL. */ public String getCacheKey() { return getUrl(); } /** - * Annotates this request with an entry retrieved for it from cache. - * Used for cache coherency support. + * Annotates this request with an entry retrieved for it from cache. Used for cache coherency + * support. * * @return This Request object to allow for chaining. */ @@ -316,9 +297,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { return this; } - /** - * Returns the annotated cache entry, or null if there isn't one. - */ + /** Returns the annotated cache entry, or null if there isn't one. */ public Cache.Entry getCacheEntry() { return mCacheEntry; } @@ -327,17 +306,18 @@ public abstract class Request<T> implements Comparable<Request<T>> { * Mark this request as canceled. * * <p>No callback will be delivered as long as either: + * * <ul> - * <li>This method is called on the same thread as the {@link ResponseDelivery} is running - * on. By default, this is the main thread. - * <li>The request subclass being used overrides cancel() and ensures that it does not - * invoke the listener in {@link #deliverResponse} after cancel() has been called in a - * thread-safe manner. + * <li>This method is called on the same thread as the {@link ResponseDelivery} is running on. + * By default, this is the main thread. + * <li>The request subclass being used overrides cancel() and ensures that it does not invoke + * the listener in {@link #deliverResponse} after cancel() has been called in a + * thread-safe manner. * </ul> * * <p>There are no guarantees if both of these conditions aren't met. */ - // @CallSuper + @CallSuper public void cancel() { synchronized (mLock) { mCanceled = true; @@ -345,9 +325,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { } } - /** - * Returns true if this request has been canceled. - */ + /** Returns true if this request has been canceled. */ public boolean isCanceled() { synchronized (mLock) { return mCanceled; @@ -355,9 +333,9 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Returns a list of extra HTTP headers to go along with this request. Can - * throw {@link AuthFailureError} as authentication may be required to - * provide these values. + * Returns a list of extra HTTP headers to go along with this request. Can throw {@link + * AuthFailureError} as authentication may be required to provide these values. + * * @throws AuthFailureError In the event of auth failure */ public Map<String, String> getHeaders() throws AuthFailureError { @@ -365,14 +343,13 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Returns a Map of POST parameters to be used for this request, or null if - * a simple GET should be used. Can throw {@link AuthFailureError} as - * authentication may be required to provide these values. + * Returns a Map of POST parameters to be used for this request, or null if a simple GET should + * be used. Can throw {@link AuthFailureError} as authentication may be required to provide + * these values. * - * <p>Note that only one of getPostParams() and getPostBody() can return a non-null - * value.</p> - * @throws AuthFailureError In the event of auth failure + * <p>Note that only one of getPostParams() and getPostBody() can return a non-null value. * + * @throws AuthFailureError In the event of auth failure * @deprecated Use {@link #getParams()} instead. */ @Deprecated @@ -381,15 +358,16 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Returns which encoding should be used when converting POST parameters returned by - * {@link #getPostParams()} into a raw POST body. + * Returns which encoding should be used when converting POST parameters returned by {@link + * #getPostParams()} into a raw POST body. * * <p>This controls both encodings: + * * <ol> - * <li>The string encoding used when converting parameter names and values into bytes prior - * to URL encoding them.</li> - * <li>The string encoding used when converting the URL encoded parameters into a raw - * byte array.</li> + * <li>The string encoding used when converting parameter names and values into bytes prior to + * URL encoding them. + * <li>The string encoding used when converting the URL encoded parameters into a raw byte + * array. * </ol> * * @deprecated Use {@link #getParamsEncoding()} instead. @@ -399,9 +377,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { return getParamsEncoding(); } - /** - * @deprecated Use {@link #getBodyContentType()} instead. - */ + /** @deprecated Use {@link #getBodyContentType()} instead. */ @Deprecated public String getPostBodyContentType() { return getBodyContentType(); @@ -411,7 +387,6 @@ public abstract class Request<T> implements Comparable<Request<T>> { * Returns the raw POST body to be sent. * * @throws AuthFailureError In the event of auth failure - * * @deprecated Use {@link #getBody()} instead. */ @Deprecated @@ -428,10 +403,10 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Returns a Map of parameters to be used for a POST or PUT request. Can throw - * {@link AuthFailureError} as authentication may be required to provide these values. + * Returns a Map of parameters to be used for a POST or PUT request. Can throw {@link + * AuthFailureError} as authentication may be required to provide these values. * - * <p>Note that you can directly override {@link #getBody()} for custom data.</p> + * <p>Note that you can directly override {@link #getBody()} for custom data. * * @throws AuthFailureError in the event of auth failure */ @@ -444,20 +419,19 @@ public abstract class Request<T> implements Comparable<Request<T>> { * {@link #getParams()} into a raw POST or PUT body. * * <p>This controls both encodings: + * * <ol> - * <li>The string encoding used when converting parameter names and values into bytes prior - * to URL encoding them.</li> - * <li>The string encoding used when converting the URL encoded parameters into a raw - * byte array.</li> + * <li>The string encoding used when converting parameter names and values into bytes prior to + * URL encoding them. + * <li>The string encoding used when converting the URL encoded parameters into a raw byte + * array. * </ol> */ protected String getParamsEncoding() { return DEFAULT_PARAMS_ENCODING; } - /** - * Returns the content type of the POST or PUT body. - */ + /** Returns the content type of the POST or PUT body. */ public String getBodyContentType() { return "application/x-www-form-urlencoded; charset=" + getParamsEncoding(); } @@ -479,9 +453,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { return null; } - /** - * Converts <code>params</code> into an application/x-www-form-urlencoded encoded string. - */ + /** Converts <code>params</code> into an application/x-www-form-urlencoded encoded string. */ private byte[] encodeParameters(Map<String, String> params, String paramsEncoding) { StringBuilder encodedParams = new StringBuilder(); try { @@ -507,9 +479,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { return this; } - /** - * Returns true if responses to this request should be cached. - */ + /** Returns true if responses to this request should be cached. */ public final boolean shouldCache() { return mShouldCache; } @@ -532,8 +502,8 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Priority values. Requests will be processed from higher priorities to - * lower priorities, in FIFO order. + * Priority values. Requests will be processed from higher priorities to lower priorities, in + * FIFO order. */ public enum Priority { LOW, @@ -542,32 +512,28 @@ public abstract class Request<T> implements Comparable<Request<T>> { IMMEDIATE } - /** - * Returns the {@link Priority} of this request; {@link Priority#NORMAL} by default. - */ + /** Returns the {@link Priority} of this request; {@link Priority#NORMAL} by default. */ public Priority getPriority() { return Priority.NORMAL; } /** - * Returns the socket timeout in milliseconds per retry attempt. (This value can be changed - * per retry attempt if a backoff is specified via backoffTimeout()). If there are no retry - * attempts remaining, this will cause delivery of a {@link TimeoutError} error. + * Returns the socket timeout in milliseconds per retry attempt. (This value can be changed per + * retry attempt if a backoff is specified via backoffTimeout()). If there are no retry attempts + * remaining, this will cause delivery of a {@link TimeoutError} error. */ public final int getTimeoutMs() { return mRetryPolicy.getCurrentTimeout(); } - /** - * Returns the retry policy that should be used for this request. - */ + /** Returns the retry policy that should be used for this request. */ public RetryPolicy getRetryPolicy() { return mRetryPolicy; } /** - * Mark this request as having a response delivered on it. This can be used - * later in the request's lifetime for suppressing identical responses. + * Mark this request as having a response delivered on it. This can be used later in the + * request's lifetime for suppressing identical responses. */ public void markDelivered() { synchronized (mLock) { @@ -575,9 +541,7 @@ public abstract class Request<T> implements Comparable<Request<T>> { } } - /** - * Returns true if this request has had a response delivered for it. - */ + /** Returns true if this request has had a response delivered for it. */ public boolean hasHadResponseDelivered() { synchronized (mLock) { return mResponseDelivered; @@ -585,19 +549,19 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Subclasses must implement this to parse the raw network response - * and return an appropriate response type. This method will be - * called from a worker thread. The response will not be delivered - * if you return null. + * Subclasses must implement this to parse the raw network response and return an appropriate + * response type. This method will be called from a worker thread. The response will not be + * delivered if you return null. + * * @param response Response from the network * @return The parsed response, or null in the case of an error */ - abstract protected Response<T> parseNetworkResponse(NetworkResponse response); + protected abstract Response<T> parseNetworkResponse(NetworkResponse response); /** * Subclasses can override this method to parse 'networkError' and return a more specific error. * - * <p>The default implementation just returns the passed 'networkError'.</p> + * <p>The default implementation just returns the passed 'networkError'. * * @param volleyError the error retrieved from the network * @return an NetworkError augmented with additional information @@ -607,17 +571,17 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Subclasses must implement this to perform delivery of the parsed - * response to their listeners. The given response is guaranteed to - * be non-null; responses that fail to parse are not delivered. - * @param response The parsed response returned by - * {@link #parseNetworkResponse(NetworkResponse)} + * Subclasses must implement this to perform delivery of the parsed response to their listeners. + * The given response is guaranteed to be non-null; responses that fail to parse are not + * delivered. + * + * @param response The parsed response returned by {@link + * #parseNetworkResponse(NetworkResponse)} */ - abstract protected void deliverResponse(T response); + protected abstract void deliverResponse(T response); /** - * Delivers error message to the ErrorListener that the Request was - * initialized with. + * Delivers error message to the ErrorListener that the Request was initialized with. * * @param error Error details */ @@ -632,8 +596,8 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * {@link NetworkRequestCompleteListener} that will receive callbacks when the request - * returns from the network. + * {@link NetworkRequestCompleteListener} that will receive callbacks when the request returns + * from the network. */ /* package */ void setNetworkRequestCompleteListener( NetworkRequestCompleteListener requestCompleteListener) { @@ -643,8 +607,9 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Notify NetworkRequestCompleteListener that a valid response has been received - * which can be used for other, waiting requests. + * Notify NetworkRequestCompleteListener that a valid response has been received which can be + * used for other, waiting requests. + * * @param response received from the network */ /* package */ void notifyListenerResponseReceived(Response<?> response) { @@ -658,8 +623,8 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Notify NetworkRequestCompleteListener that the network request did not result in - * a response which can be used for other, waiting requests. + * Notify NetworkRequestCompleteListener that the network request did not result in a response + * which can be used for other, waiting requests. */ /* package */ void notifyListenerResponseNotUsable() { NetworkRequestCompleteListener listener; @@ -672,8 +637,8 @@ public abstract class Request<T> implements Comparable<Request<T>> { } /** - * Our comparator sorts from high to low priority, and secondarily by - * sequence number to provide FIFO ordering. + * Our comparator sorts from high to low priority, and secondarily by sequence number to provide + * FIFO ordering. */ @Override public int compareTo(Request<T> other) { @@ -682,15 +647,19 @@ public abstract class Request<T> implements Comparable<Request<T>> { // High-priority requests are "lesser" so they are sorted to the front. // Equal priorities are sorted by sequence number to provide FIFO ordering. - return left == right ? - this.mSequence - other.mSequence : - right.ordinal() - left.ordinal(); + return left == right ? this.mSequence - other.mSequence : right.ordinal() - left.ordinal(); } @Override public String toString() { String trafficStatsTag = "0x" + Integer.toHexString(getTrafficStatsTag()); - return (mCanceled ? "[X] " : "[ ] ") + getUrl() + " " + trafficStatsTag + " " - + getPriority() + " " + mSequence; + return (isCanceled() ? "[X] " : "[ ] ") + + getUrl() + + " " + + trafficStatsTag + + " " + + getPriority() + + " " + + mSequence; } } diff --git a/src/main/java/com/android/volley/RequestQueue.java b/src/main/java/com/android/volley/RequestQueue.java index 45679a5..a9312be 100644 --- a/src/main/java/com/android/volley/RequestQueue.java +++ b/src/main/java/com/android/volley/RequestQueue.java @@ -18,7 +18,6 @@ package com.android.volley; import android.os.Handler; import android.os.Looper; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -29,13 +28,16 @@ import java.util.concurrent.atomic.AtomicInteger; /** * A request dispatch queue with a thread pool of dispatchers. * - * Calling {@link #add(Request)} will enqueue the given Request for dispatch, - * resolving from either cache or network on a worker thread, and then delivering - * a parsed response on the main thread. + * <p>Calling {@link #add(Request)} will enqueue the given Request for dispatch, resolving from + * either cache or network on a worker thread, and then delivering a parsed response on the main + * thread. */ public class RequestQueue { /** Callback interface for completed requests. */ + // TODO: This should not be a generic class, because the request type can't be determined at + // compile time, so all calls to onRequestFinished are unsafe. However, changing this would be + // an API-breaking change. See also: https://github.com/google/volley/pull/109 public interface RequestFinishedListener<T> { /** Called when a request has finished processing. */ void onRequestFinished(Request<T> request); @@ -45,19 +47,16 @@ public class RequestQueue { private final AtomicInteger mSequenceGenerator = new AtomicInteger(); /** - * The set of all requests currently being processed by this RequestQueue. A Request - * will be in this set if it is waiting in any queue or currently being processed by - * any dispatcher. + * The set of all requests currently being processed by this RequestQueue. A Request will be in + * this set if it is waiting in any queue or currently being processed by any dispatcher. */ - private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>(); + private final Set<Request<?>> mCurrentRequests = new HashSet<>(); /** The cache triage queue. */ - private final PriorityBlockingQueue<Request<?>> mCacheQueue = - new PriorityBlockingQueue<>(); + private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<>(); /** The queue of requests that are actually going out to the network. */ - private final PriorityBlockingQueue<Request<?>> mNetworkQueue = - new PriorityBlockingQueue<>(); + private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<>(); /** Number of network request dispatcher threads to start. */ private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4; @@ -77,8 +76,7 @@ public class RequestQueue { /** The cache dispatcher. */ private CacheDispatcher mCacheDispatcher; - private final List<RequestFinishedListener> mFinishedListeners = - new ArrayList<>(); + private final List<RequestFinishedListener> mFinishedListeners = new ArrayList<>(); /** * Creates the worker pool. Processing will not begin until {@link #start()} is called. @@ -88,8 +86,8 @@ public class RequestQueue { * @param threadPoolSize Number of network dispatcher threads to create * @param delivery A ResponseDelivery interface for posting responses and errors */ - public RequestQueue(Cache cache, Network network, int threadPoolSize, - ResponseDelivery delivery) { + public RequestQueue( + Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { mCache = cache; mNetwork = network; mDispatchers = new NetworkDispatcher[threadPoolSize]; @@ -104,7 +102,10 @@ public class RequestQueue { * @param threadPoolSize Number of network dispatcher threads to create */ public RequestQueue(Cache cache, Network network, int threadPoolSize) { - this(cache, network, threadPoolSize, + this( + cache, + network, + threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); } @@ -118,27 +119,23 @@ public class RequestQueue { this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE); } - /** - * Starts the dispatchers in this queue. - */ + /** Starts the dispatchers in this queue. */ public void start() { - stop(); // Make sure any currently running dispatchers are stopped. + stop(); // Make sure any currently running dispatchers are stopped. // Create the cache dispatcher and start it. mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); // Create network dispatchers (and corresponding threads) up to the pool size. for (int i = 0; i < mDispatchers.length; i++) { - NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, - mCache, mDelivery); + NetworkDispatcher networkDispatcher = + new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } } - /** - * Stops the cache and network dispatchers. - */ + /** Stops the cache and network dispatchers. */ public void stop() { if (mCacheDispatcher != null) { mCacheDispatcher.quit(); @@ -150,23 +147,19 @@ public class RequestQueue { } } - /** - * Gets a sequence number. - */ + /** Gets a sequence number. */ public int getSequenceNumber() { return mSequenceGenerator.incrementAndGet(); } - /** - * Gets the {@link Cache} instance being used. - */ + /** Gets the {@link Cache} instance being used. */ public Cache getCache() { return mCache; } /** - * A simple predicate or filter interface for Requests, for use by - * {@link RequestQueue#cancelAll(RequestFilter)}. + * A simple predicate or filter interface for Requests, for use by {@link + * RequestQueue#cancelAll(RequestFilter)}. */ public interface RequestFilter { boolean apply(Request<?> request); @@ -174,6 +167,7 @@ public class RequestQueue { /** * Cancels all requests in this queue for which the given filter applies. + * * @param filter The filtering function to use */ public void cancelAll(RequestFilter filter) { @@ -187,23 +181,25 @@ public class RequestQueue { } /** - * Cancels all requests in this queue with the given tag. Tag must be non-null - * and equality is by identity. + * Cancels all requests in this queue with the given tag. Tag must be non-null and equality is + * by identity. */ public void cancelAll(final Object tag) { if (tag == null) { throw new IllegalArgumentException("Cannot cancelAll with a null tag"); } - cancelAll(new RequestFilter() { - @Override - public boolean apply(Request<?> request) { - return request.getTag() == tag; - } - }); + cancelAll( + new RequestFilter() { + @Override + public boolean apply(Request<?> request) { + return request.getTag() == tag; + } + }); } /** * Adds a Request to the dispatch queue. + * * @param request The request to service * @return The passed-in request */ @@ -225,37 +221,35 @@ public class RequestQueue { } mCacheQueue.add(request); return request; - } + } /** * Called from {@link Request#finish(String)}, indicating that processing of the given request * has finished. */ + @SuppressWarnings("unchecked") // see above note on RequestFinishedListener <T> void finish(Request<T> request) { // Remove from the set of requests currently being processed. synchronized (mCurrentRequests) { mCurrentRequests.remove(request); } synchronized (mFinishedListeners) { - for (RequestFinishedListener<T> listener : mFinishedListeners) { - listener.onRequestFinished(request); - } + for (RequestFinishedListener<T> listener : mFinishedListeners) { + listener.onRequestFinished(request); + } } - } - public <T> void addRequestFinishedListener(RequestFinishedListener<T> listener) { - synchronized (mFinishedListeners) { - mFinishedListeners.add(listener); - } + public <T> void addRequestFinishedListener(RequestFinishedListener<T> listener) { + synchronized (mFinishedListeners) { + mFinishedListeners.add(listener); + } } - /** - * Remove a RequestFinishedListener. Has no effect if listener was not previously added. - */ - public <T> void removeRequestFinishedListener(RequestFinishedListener<T> listener) { - synchronized (mFinishedListeners) { - mFinishedListeners.remove(listener); - } + /** Remove a RequestFinishedListener. Has no effect if listener was not previously added. */ + public <T> void removeRequestFinishedListener(RequestFinishedListener<T> listener) { + synchronized (mFinishedListeners) { + mFinishedListeners.remove(listener); + } } } diff --git a/src/main/java/com/android/volley/Response.java b/src/main/java/com/android/volley/Response.java index 1fe7215..2f50e2d 100644 --- a/src/main/java/com/android/volley/Response.java +++ b/src/main/java/com/android/volley/Response.java @@ -32,23 +32,23 @@ public class Response<T> { /** Callback interface for delivering error responses. */ public interface ErrorListener { /** - * Callback method that an error has been occurred with the - * provided error code and optional user-readable message. + * Callback method that an error has been occurred with the provided error code and optional + * user-readable message. */ void onErrorResponse(VolleyError error); } /** Returns a successful response containing the parsed result. */ public static <T> Response<T> success(T result, Cache.Entry cacheEntry) { - return new Response<T>(result, cacheEntry); + return new Response<>(result, cacheEntry); } /** - * Returns a failed response containing the given error code and an optional - * localized message displayed to the user. + * Returns a failed response containing the given error code and an optional localized message + * displayed to the user. */ public static <T> Response<T> error(VolleyError error) { - return new Response<T>(error); + return new Response<>(error); } /** Parsed response, or null in the case of error. */ @@ -63,14 +63,11 @@ public class Response<T> { /** True if this response was a soft-expired one and a second one MAY be coming. */ public boolean intermediate = false; - /** - * Returns whether this response is considered successful. - */ + /** Returns whether this response is considered successful. */ public boolean isSuccess() { return error == null; } - private Response(T result, Cache.Entry cacheEntry) { this.result = result; this.cacheEntry = cacheEntry; diff --git a/src/main/java/com/android/volley/ResponseDelivery.java b/src/main/java/com/android/volley/ResponseDelivery.java index bef3df5..10aa137 100644 --- a/src/main/java/com/android/volley/ResponseDelivery.java +++ b/src/main/java/com/android/volley/ResponseDelivery.java @@ -17,19 +17,15 @@ package com.android.volley; public interface ResponseDelivery { - /** - * Parses a response from the network or cache and delivers it. - */ + /** Parses a response from the network or cache and delivers it. */ void postResponse(Request<?> request, Response<?> response); /** - * Parses a response from the network or cache and delivers it. The provided - * Runnable will be executed after delivery. + * Parses a response from the network or cache and delivers it. The provided Runnable will be + * executed after delivery. */ void postResponse(Request<?> request, Response<?> response, Runnable runnable); - /** - * Posts an error for the given request. - */ + /** Posts an error for the given request. */ void postError(Request<?> request, VolleyError error); } diff --git a/src/main/java/com/android/volley/RetryPolicy.java b/src/main/java/com/android/volley/RetryPolicy.java index f58678d..aa6af43 100644 --- a/src/main/java/com/android/volley/RetryPolicy.java +++ b/src/main/java/com/android/volley/RetryPolicy.java @@ -16,26 +16,21 @@ package com.android.volley; -/** - * Retry policy for a request. - */ +/** Retry policy for a request. */ public interface RetryPolicy { - /** - * Returns the current timeout (used for logging). - */ + /** Returns the current timeout (used for logging). */ int getCurrentTimeout(); - /** - * Returns the current retry count (used for logging). - */ + /** Returns the current retry count (used for logging). */ int getCurrentRetryCount(); /** * Prepares for the next retry by applying a backoff to the timeout. + * * @param error The error code of the last attempt. - * @throws VolleyError In the event that the retry could not be performed (for example if we - * ran out of attempts), the passed in error is thrown. + * @throws VolleyError In the event that the retry could not be performed (for example if we ran + * out of attempts), the passed in error is thrown. */ void retry(VolleyError error) throws VolleyError; } diff --git a/src/main/java/com/android/volley/ServerError.java b/src/main/java/com/android/volley/ServerError.java index 7b33c33..84b2eb4 100644 --- a/src/main/java/com/android/volley/ServerError.java +++ b/src/main/java/com/android/volley/ServerError.java @@ -16,9 +16,7 @@ package com.android.volley; -/** - * Indicates that the server responded with an error response. - */ +/** Indicates that the server responded with an error response. */ @SuppressWarnings("serial") public class ServerError extends VolleyError { public ServerError(NetworkResponse networkResponse) { @@ -29,4 +27,3 @@ public class ServerError extends VolleyError { super(); } } - diff --git a/src/main/java/com/android/volley/TimeoutError.java b/src/main/java/com/android/volley/TimeoutError.java index 0b5d6ac..227ae08 100644 --- a/src/main/java/com/android/volley/TimeoutError.java +++ b/src/main/java/com/android/volley/TimeoutError.java @@ -16,8 +16,6 @@ package com.android.volley; -/** - * Indicates that the connection or the socket timed out. - */ +/** Indicates that the connection or the socket timed out. */ @SuppressWarnings("serial") -public class TimeoutError extends VolleyError { } +public class TimeoutError extends VolleyError {} diff --git a/src/main/java/com/android/volley/VolleyError.java b/src/main/java/com/android/volley/VolleyError.java index 1471d40..45086da 100644 --- a/src/main/java/com/android/volley/VolleyError.java +++ b/src/main/java/com/android/volley/VolleyError.java @@ -16,9 +16,7 @@ package com.android.volley; -/** - * Exception style class encapsulating Volley errors - */ +/** Exception style class encapsulating Volley errors */ @SuppressWarnings("serial") public class VolleyError extends Exception { public final NetworkResponse networkResponse; @@ -33,8 +31,8 @@ public class VolleyError extends Exception { } public VolleyError(String exceptionMessage) { - super(exceptionMessage); - networkResponse = null; + super(exceptionMessage); + networkResponse = null; } public VolleyError(String exceptionMessage, Throwable reason) { @@ -48,10 +46,10 @@ public class VolleyError extends Exception { } /* package */ void setNetworkTimeMs(long networkTimeMs) { - this.networkTimeMs = networkTimeMs; + this.networkTimeMs = networkTimeMs; } public long getNetworkTimeMs() { - return networkTimeMs; + return networkTimeMs; } } diff --git a/src/main/java/com/android/volley/VolleyLog.java b/src/main/java/com/android/volley/VolleyLog.java index fc776e5..8477668 100644 --- a/src/main/java/com/android/volley/VolleyLog.java +++ b/src/main/java/com/android/volley/VolleyLog.java @@ -18,15 +18,14 @@ package com.android.volley; import android.os.SystemClock; import android.util.Log; - import java.util.ArrayList; import java.util.List; import java.util.Locale; /** * Logging helper class. - * <p> - * to see Volley logs call:<br> + * + * <p>to see Volley logs call:<br> * {@code <android-sdk>/platform-tools/adb shell setprop log.tag.Volley VERBOSE} */ public class VolleyLog { @@ -35,11 +34,15 @@ public class VolleyLog { public static boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE); /** - * Customize the log tag for your application, so that other apps - * using Volley don't mix their logs with yours. - * <br> - * Enable the log property for your tag before starting your app: - * <br> + * {@link Class#getName()} uses reflection and calling it on a potentially hot code path may + * have some cost. To minimize this cost we fetch class name once here and use it later. + */ + private static final String CLASS_NAME = VolleyLog.class.getName(); + + /** + * Customize the log tag for your application, so that other apps using Volley don't mix their + * logs with yours. <br> + * Enable the log property for your tag before starting your app: <br> * {@code adb shell setprop log.tag.<tag>} */ public static void setTag(String tag) { @@ -77,8 +80,8 @@ public class VolleyLog { } /** - * Formats the caller's provided message and prepends useful info like - * calling thread ID and method name. + * Formats the caller's provided message and prepends useful info like calling thread ID and + * method name. */ private static String buildMessage(String format, Object... args) { String msg = (args == null) ? format : String.format(Locale.US, format, args); @@ -88,8 +91,8 @@ public class VolleyLog { // Walk up the stack looking for the first caller outside of VolleyLog. // It will be at least two frames up, so start there. for (int i = 2; i < trace.length; i++) { - Class<?> clazz = trace[i].getClass(); - if (!clazz.equals(VolleyLog.class)) { + String clazz = trace[i].getClassName(); + if (!clazz.equals(VolleyLog.CLASS_NAME)) { String callingClass = trace[i].getClassName(); callingClass = callingClass.substring(callingClass.lastIndexOf('.') + 1); callingClass = callingClass.substring(callingClass.lastIndexOf('$') + 1); @@ -98,13 +101,10 @@ public class VolleyLog { break; } } - return String.format(Locale.US, "[%d] %s: %s", - Thread.currentThread().getId(), caller, msg); + return String.format(Locale.US, "[%d] %s: %s", Thread.currentThread().getId(), caller, msg); } - /** - * A simple event log with records containing a name, thread ID, and timestamp. - */ + /** A simple event log with records containing a name, thread ID, and timestamp. */ static class MarkerLog { public static final boolean ENABLED = VolleyLog.DEBUG; @@ -123,7 +123,7 @@ public class VolleyLog { } } - private final List<Marker> mMarkers = new ArrayList<Marker>(); + private final List<Marker> mMarkers = new ArrayList<>(); private boolean mFinished = false; /** Adds a marker to this log with the specified name. */ @@ -136,8 +136,9 @@ public class VolleyLog { } /** - * Closes the log, dumping it to logcat if the time difference between - * the first and last markers is greater than {@link #MIN_DURATION_FOR_LOGGING_MS}. + * Closes the log, dumping it to logcat if the time difference between the first and last + * markers is greater than {@link #MIN_DURATION_FOR_LOGGING_MS}. + * * @param header Header string to print above the marker log. */ public synchronized void finish(String header) { diff --git a/src/main/java/com/android/volley/toolbox/AdaptedHttpStack.java b/src/main/java/com/android/volley/toolbox/AdaptedHttpStack.java index e5dc62b..c75c25f 100644 --- a/src/main/java/com/android/volley/toolbox/AdaptedHttpStack.java +++ b/src/main/java/com/android/volley/toolbox/AdaptedHttpStack.java @@ -18,14 +18,12 @@ package com.android.volley.toolbox; import com.android.volley.AuthFailureError; import com.android.volley.Header; import com.android.volley.Request; - -import org.apache.http.conn.ConnectTimeoutException; - import java.io.IOException; import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.apache.http.conn.ConnectTimeoutException; /** * {@link BaseHttpStack} implementation wrapping a {@link HttpStack}. @@ -43,12 +41,11 @@ class AdaptedHttpStack extends BaseHttpStack { } @Override - public HttpResponse executeRequest( - Request<?> request, Map<String, String> additionalHeaders) + public HttpResponse executeRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { org.apache.http.HttpResponse apacheResp; try { - apacheResp = mHttpStack.performRequest(request, additionalHeaders); + apacheResp = mHttpStack.performRequest(request, additionalHeaders); } catch (ConnectTimeoutException e) { // BasicNetwork won't know that this exception should be retried like a timeout, since // it's an Apache-specific error, so wrap it in a standard timeout exception. diff --git a/src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java b/src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java index 73468b9..72271fc 100644 --- a/src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java +++ b/src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java @@ -16,8 +16,6 @@ package com.android.volley.toolbox; -import com.android.volley.AuthFailureError; - import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerFuture; @@ -25,10 +23,12 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.support.annotation.VisibleForTesting; +import com.android.volley.AuthFailureError; /** - * An Authenticator that uses {@link AccountManager} to get auth - * tokens of a specified type for a specified account. + * An Authenticator that uses {@link AccountManager} to get auth tokens of a specified type for a + * specified account. */ // TODO: Update this to account for runtime permissions @SuppressLint("MissingPermission") @@ -40,45 +40,46 @@ public class AndroidAuthenticator implements Authenticator { /** * Creates a new authenticator. + * * @param context Context for accessing AccountManager * @param account Account to authenticate as * @param authTokenType Auth token type passed to AccountManager */ public AndroidAuthenticator(Context context, Account account, String authTokenType) { - this(context, account, authTokenType, false); + this(context, account, authTokenType, /* notifyAuthFailure= */ false); } /** * Creates a new authenticator. + * * @param context Context for accessing AccountManager * @param account Account to authenticate as * @param authTokenType Auth token type passed to AccountManager * @param notifyAuthFailure Whether to raise a notification upon auth failure */ - public AndroidAuthenticator(Context context, Account account, String authTokenType, - boolean notifyAuthFailure) { + public AndroidAuthenticator( + Context context, Account account, String authTokenType, boolean notifyAuthFailure) { this(AccountManager.get(context), account, authTokenType, notifyAuthFailure); } - // Visible for testing. Allows injection of a mock AccountManager. - AndroidAuthenticator(AccountManager accountManager, Account account, - String authTokenType, boolean notifyAuthFailure) { + @VisibleForTesting + AndroidAuthenticator( + AccountManager accountManager, + Account account, + String authTokenType, + boolean notifyAuthFailure) { mAccountManager = accountManager; mAccount = account; mAuthTokenType = authTokenType; mNotifyAuthFailure = notifyAuthFailure; } - /** - * Returns the Account being used by this authenticator. - */ + /** Returns the Account being used by this authenticator. */ public Account getAccount() { return mAccount; } - /** - * Returns the Auth Token Type used by this authenticator. - */ + /** Returns the Auth Token Type used by this authenticator. */ public String getAuthTokenType() { return mAuthTokenType; } @@ -87,8 +88,13 @@ public class AndroidAuthenticator implements Authenticator { @SuppressWarnings("deprecation") @Override public String getAuthToken() throws AuthFailureError { - AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(mAccount, - mAuthTokenType, mNotifyAuthFailure, null, null); + AccountManagerFuture<Bundle> future = + mAccountManager.getAuthToken( + mAccount, + mAuthTokenType, + mNotifyAuthFailure, + /* callback= */ null, + /* handler= */ null); Bundle result; try { result = future.getResult(); diff --git a/src/main/java/com/android/volley/toolbox/Authenticator.java b/src/main/java/com/android/volley/toolbox/Authenticator.java index adfc996..2ba43db 100644 --- a/src/main/java/com/android/volley/toolbox/Authenticator.java +++ b/src/main/java/com/android/volley/toolbox/Authenticator.java @@ -18,9 +18,7 @@ package com.android.volley.toolbox; import com.android.volley.AuthFailureError; -/** - * An interface for interacting with auth tokens. - */ +/** An interface for interacting with auth tokens. */ public interface Authenticator { /** * Synchronously retrieves an auth token. @@ -29,8 +27,6 @@ public interface Authenticator { */ String getAuthToken() throws AuthFailureError; - /** - * Invalidates the provided auth token. - */ + /** Invalidates the provided auth token. */ void invalidateAuthToken(String authToken); } diff --git a/src/main/java/com/android/volley/toolbox/BaseHttpStack.java b/src/main/java/com/android/volley/toolbox/BaseHttpStack.java index 257f75c..4f596e1 100644 --- a/src/main/java/com/android/volley/toolbox/BaseHttpStack.java +++ b/src/main/java/com/android/volley/toolbox/BaseHttpStack.java @@ -18,20 +18,18 @@ package com.android.volley.toolbox; import com.android.volley.AuthFailureError; import com.android.volley.Header; import com.android.volley.Request; - -import org.apache.http.ProtocolVersion; -import org.apache.http.StatusLine; -import org.apache.http.entity.BasicHttpEntity; -import org.apache.http.message.BasicHeader; -import org.apache.http.message.BasicHttpResponse; -import org.apache.http.message.BasicStatusLine; - import java.io.IOException; import java.io.InputStream; import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.apache.http.ProtocolVersion; +import org.apache.http.StatusLine; +import org.apache.http.entity.BasicHttpEntity; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicHttpResponse; +import org.apache.http.message.BasicStatusLine; /** An HTTP stack abstraction. */ @SuppressWarnings("deprecation") // for HttpStack @@ -44,8 +42,8 @@ public abstract class BaseHttpStack implements HttpStack { * and the Content-Type header is set to request.getPostBodyContentType(). * * @param request the request to perform - * @param additionalHeaders additional headers to be sent together with - * {@link Request#getHeaders()} + * @param additionalHeaders additional headers to be sent together with {@link + * Request#getHeaders()} * @return the {@link HttpResponse} * @throws SocketTimeoutException if the request times out * @throws IOException if another I/O error occurs during the request @@ -57,10 +55,10 @@ public abstract class BaseHttpStack implements HttpStack { /** * @deprecated use {@link #executeRequest} instead to avoid a dependency on the deprecated - * Apache HTTP library. Nothing in Volley's own source calls this method. However, since - * {@link BasicNetwork#mHttpStack} is exposed to subclasses, we provide this implementation in - * case legacy client apps are dependent on that field. This method may be removed in a future - * release of Volley. + * Apache HTTP library. Nothing in Volley's own source calls this method. However, since + * {@link BasicNetwork#mHttpStack} is exposed to subclasses, we provide this implementation + * in case legacy client apps are dependent on that field. This method may be removed in a + * future release of Volley. */ @Deprecated @Override @@ -70,8 +68,9 @@ public abstract class BaseHttpStack implements HttpStack { HttpResponse response = executeRequest(request, additionalHeaders); ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1); - StatusLine statusLine = new BasicStatusLine( - protocolVersion, response.getStatusCode(), "" /* reasonPhrase */); + StatusLine statusLine = + new BasicStatusLine( + protocolVersion, response.getStatusCode(), /* reasonPhrase= */ ""); BasicHttpResponse apacheResponse = new BasicHttpResponse(statusLine); List<org.apache.http.Header> headers = new ArrayList<>(); diff --git a/src/main/java/com/android/volley/toolbox/BasicNetwork.java b/src/main/java/com/android/volley/toolbox/BasicNetwork.java index 5330733..b527cb9 100644 --- a/src/main/java/com/android/volley/toolbox/BasicNetwork.java +++ b/src/main/java/com/android/volley/toolbox/BasicNetwork.java @@ -17,7 +17,6 @@ package com.android.volley.toolbox; import android.os.SystemClock; - import com.android.volley.AuthFailureError; import com.android.volley.Cache; import com.android.volley.Cache.Entry; @@ -33,7 +32,6 @@ import com.android.volley.ServerError; import com.android.volley.TimeoutError; import com.android.volley.VolleyError; import com.android.volley.VolleyLog; - import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; @@ -48,9 +46,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; -/** - * A network performing Volley requests over an {@link HttpStack}. - */ +/** A network performing Volley requests over an {@link HttpStack}. */ public class BasicNetwork implements Network { protected static final boolean DEBUG = VolleyLog.DEBUG; @@ -60,10 +56,9 @@ public class BasicNetwork implements Network { /** * @deprecated Should never have been exposed in the API. This field may be removed in a future - * release of Volley. + * release of Volley. */ - @Deprecated - protected final HttpStack mHttpStack; + @Deprecated protected final HttpStack mHttpStack; private final BaseHttpStack mBaseHttpStack; @@ -72,7 +67,7 @@ public class BasicNetwork implements Network { /** * @param httpStack HTTP stack to be used * @deprecated use {@link #BasicNetwork(BaseHttpStack)} instead to avoid depending on Apache - * HTTP. This method may be removed in a future release of Volley. + * HTTP. This method may be removed in a future release of Volley. */ @Deprecated public BasicNetwork(HttpStack httpStack) { @@ -85,8 +80,7 @@ public class BasicNetwork implements Network { * @param httpStack HTTP stack to be used * @param pool a buffer pool that improves GC performance in copy operations * @deprecated use {@link #BasicNetwork(BaseHttpStack, ByteArrayPool)} instead to avoid - * depending on Apache HTTP. This method may be removed in a future release of - * Volley. + * depending on Apache HTTP. This method may be removed in a future release of Volley. */ @Deprecated public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) { @@ -95,9 +89,7 @@ public class BasicNetwork implements Network { mPool = pool; } - /** - * @param httpStack HTTP stack to be used - */ + /** @param httpStack HTTP stack to be used */ public BasicNetwork(BaseHttpStack httpStack) { // If a pool isn't passed in, then build a small default pool that will give us a lot of // benefit and not use too much memory. @@ -136,24 +128,32 @@ public class BasicNetwork implements Network { if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) { Entry entry = request.getCacheEntry(); if (entry == null) { - return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, null, true, - SystemClock.elapsedRealtime() - requestStart, responseHeaders); + return new NetworkResponse( + HttpURLConnection.HTTP_NOT_MODIFIED, + /* data= */ null, + /* notModified= */ true, + SystemClock.elapsedRealtime() - requestStart, + responseHeaders); } // Combine cached and response headers so the response will be complete. List<Header> combinedHeaders = combineHeaders(responseHeaders, entry); - return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, entry.data, - true, SystemClock.elapsedRealtime() - requestStart, combinedHeaders); + return new NetworkResponse( + HttpURLConnection.HTTP_NOT_MODIFIED, + entry.data, + /* notModified= */ true, + SystemClock.elapsedRealtime() - requestStart, + combinedHeaders); } // Some responses such as 204s do not have content. We must check. InputStream inputStream = httpResponse.getContent(); if (inputStream != null) { - responseContents = - inputStreamToBytes(inputStream, httpResponse.getContentLength()); + responseContents = + inputStreamToBytes(inputStream, httpResponse.getContentLength()); } else { - // Add 0 byte response as a way of honestly representing a - // no-content request. - responseContents = new byte[0]; + // Add 0 byte response as a way of honestly representing a + // no-content request. + responseContents = new byte[0]; } // if the request is slow, log it. @@ -163,8 +163,12 @@ public class BasicNetwork implements Network { if (statusCode < 200 || statusCode > 299) { throw new IOException(); } - return new NetworkResponse(statusCode, responseContents, false, - SystemClock.elapsedRealtime() - requestStart, responseHeaders); + return new NetworkResponse( + statusCode, + responseContents, + /* notModified= */ false, + SystemClock.elapsedRealtime() - requestStart, + responseHeaders); } catch (SocketTimeoutException e) { attemptRetryOnException("socket", request, new TimeoutError()); } catch (MalformedURLException e) { @@ -179,19 +183,24 @@ public class BasicNetwork implements Network { VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl()); NetworkResponse networkResponse; if (responseContents != null) { - networkResponse = new NetworkResponse(statusCode, responseContents, false, - SystemClock.elapsedRealtime() - requestStart, responseHeaders); - if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED || - statusCode == HttpURLConnection.HTTP_FORBIDDEN) { - attemptRetryOnException("auth", - request, new AuthFailureError(networkResponse)); + networkResponse = + new NetworkResponse( + statusCode, + responseContents, + /* notModified= */ false, + SystemClock.elapsedRealtime() - requestStart, + responseHeaders); + if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED + || statusCode == HttpURLConnection.HTTP_FORBIDDEN) { + attemptRetryOnException( + "auth", request, new AuthFailureError(networkResponse)); } else if (statusCode >= 400 && statusCode <= 499) { // Don't retry other client errors. throw new ClientError(networkResponse); } else if (statusCode >= 500 && statusCode <= 599) { if (request.shouldRetryServerErrors()) { - attemptRetryOnException("server", - request, new ServerError(networkResponse)); + attemptRetryOnException( + "server", request, new ServerError(networkResponse)); } else { throw new ServerError(networkResponse); } @@ -206,26 +215,29 @@ public class BasicNetwork implements Network { } } - /** - * Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete. - */ - private void logSlowRequests(long requestLifetime, Request<?> request, - byte[] responseContents, int statusCode) { + /** Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete. */ + private void logSlowRequests( + long requestLifetime, Request<?> request, byte[] responseContents, int statusCode) { if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) { - VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], " + - "[rc=%d], [retryCount=%s]", request, requestLifetime, + VolleyLog.d( + "HTTP response for request=<%s> [lifetime=%d], [size=%s], " + + "[rc=%d], [retryCount=%s]", + request, + requestLifetime, responseContents != null ? responseContents.length : "null", - statusCode, request.getRetryPolicy().getCurrentRetryCount()); + statusCode, + request.getRetryPolicy().getCurrentRetryCount()); } } /** * Attempts to prepare the request for a retry. If there are no more attempts remaining in the * request's retry policy, a timeout exception is thrown. + * * @param request The request to use. */ - private static void attemptRetryOnException(String logPrefix, Request<?> request, - VolleyError exception) throws VolleyError { + private static void attemptRetryOnException( + String logPrefix, Request<?> request, VolleyError exception) throws VolleyError { RetryPolicy retryPolicy = request.getRetryPolicy(); int oldTimeout = request.getTimeoutMs(); @@ -252,8 +264,8 @@ public class BasicNetwork implements Network { } if (entry.lastModified > 0) { - headers.put("If-Modified-Since", - HttpHeaderParser.formatEpochAsRfc1123(entry.lastModified)); + headers.put( + "If-Modified-Since", HttpHeaderParser.formatEpochAsRfc1123(entry.lastModified)); } return headers; @@ -267,8 +279,7 @@ public class BasicNetwork implements Network { /** Reads the contents of an InputStream into a byte[]. */ private byte[] inputStreamToBytes(InputStream in, int contentLength) throws IOException, ServerError { - PoolingByteArrayOutputStream bytes = - new PoolingByteArrayOutputStream(mPool, contentLength); + PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(mPool, contentLength); byte[] buffer = null; try { if (in == null) { @@ -300,7 +311,7 @@ public class BasicNetwork implements Network { * Converts Headers[] to Map<String, String>. * * @deprecated Should never have been exposed in the API. This method may be removed in a future - * release of Volley. + * release of Volley. */ @Deprecated protected static Map<String, String> convertHeaders(Header[] headers) { @@ -325,8 +336,7 @@ public class BasicNetwork implements Network { private static List<Header> combineHeaders(List<Header> responseHeaders, Entry entry) { // First, create a case-insensitive set of header names from the network // response. - Set<String> headerNamesFromNetworkResponse = - new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + Set<String> headerNamesFromNetworkResponse = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); if (!responseHeaders.isEmpty()) { for (Header header : responseHeaders) { headerNamesFromNetworkResponse.add(header.getName()); diff --git a/src/main/java/com/android/volley/toolbox/ByteArrayPool.java b/src/main/java/com/android/volley/toolbox/ByteArrayPool.java index c8ca2c2..0134fa2 100644 --- a/src/main/java/com/android/volley/toolbox/ByteArrayPool.java +++ b/src/main/java/com/android/volley/toolbox/ByteArrayPool.java @@ -19,42 +19,41 @@ package com.android.volley.toolbox; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.LinkedList; import java.util.List; /** - * ByteArrayPool is a source and repository of <code>byte[]</code> objects. Its purpose is to - * supply those buffers to consumers who need to use them for a short period of time and then - * dispose of them. Simply creating and disposing such buffers in the conventional manner can - * considerable heap churn and garbage collection delays on Android, which lacks good management of - * short-lived heap objects. It may be advantageous to trade off some memory in the form of a - * permanently allocated pool of buffers in order to gain heap performance improvements; that is - * what this class does. - * <p> - * A good candidate user for this class is something like an I/O system that uses large temporary - * <code>byte[]</code> buffers to copy data around. In these use cases, often the consumer wants - * the buffer to be a certain minimum size to ensure good performance (e.g. when copying data chunks - * off of a stream), but doesn't mind if the buffer is larger than the minimum. Taking this into - * account and also to maximize the odds of being able to reuse a recycled buffer, this class is - * free to return buffers larger than the requested size. The caller needs to be able to gracefully - * deal with getting buffers any size over the minimum. - * <p> - * If there is not a suitably-sized buffer in its recycling pool when a buffer is requested, this + * ByteArrayPool is a source and repository of <code>byte[]</code> objects. Its purpose is to supply + * those buffers to consumers who need to use them for a short period of time and then dispose of + * them. Simply creating and disposing such buffers in the conventional manner can considerable heap + * churn and garbage collection delays on Android, which lacks good management of short-lived heap + * objects. It may be advantageous to trade off some memory in the form of a permanently allocated + * pool of buffers in order to gain heap performance improvements; that is what this class does. + * + * <p>A good candidate user for this class is something like an I/O system that uses large temporary + * <code>byte[]</code> buffers to copy data around. In these use cases, often the consumer wants the + * buffer to be a certain minimum size to ensure good performance (e.g. when copying data chunks off + * of a stream), but doesn't mind if the buffer is larger than the minimum. Taking this into account + * and also to maximize the odds of being able to reuse a recycled buffer, this class is free to + * return buffers larger than the requested size. The caller needs to be able to gracefully deal + * with getting buffers any size over the minimum. + * + * <p>If there is not a suitably-sized buffer in its recycling pool when a buffer is requested, this * class will allocate a new buffer and return it. - * <p> - * This class has no special ownership of buffers it creates; the caller is free to take a buffer - * it receives from this pool, use it permanently, and never return it to the pool; additionally, - * it is not harmful to return to this pool a buffer that was allocated elsewhere, provided there - * are no other lingering references to it. - * <p> - * This class ensures that the total size of the buffers in its recycling pool never exceeds a + * + * <p>This class has no special ownership of buffers it creates; the caller is free to take a buffer + * it receives from this pool, use it permanently, and never return it to the pool; additionally, it + * is not harmful to return to this pool a buffer that was allocated elsewhere, provided there are + * no other lingering references to it. + * + * <p>This class ensures that the total size of the buffers in its recycling pool never exceeds a * certain byte limit. When a buffer is returned that would cause the pool to exceed the limit, * least-recently-used buffers are disposed. */ public class ByteArrayPool { /** The buffer pool, arranged both by last use and by buffer size */ - private final List<byte[]> mBuffersByLastUse = new LinkedList<byte[]>(); - private final List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64); + private final List<byte[]> mBuffersByLastUse = new ArrayList<>(); + + private final List<byte[]> mBuffersBySize = new ArrayList<>(64); /** The total size of the buffers in the pool */ private int mCurrentSize = 0; @@ -66,16 +65,15 @@ public class ByteArrayPool { private final int mSizeLimit; /** Compares buffers by size */ - protected static final Comparator<byte[]> BUF_COMPARATOR = new Comparator<byte[]>() { - @Override - public int compare(byte[] lhs, byte[] rhs) { - return lhs.length - rhs.length; - } - }; + protected static final Comparator<byte[]> BUF_COMPARATOR = + new Comparator<byte[]>() { + @Override + public int compare(byte[] lhs, byte[] rhs) { + return lhs.length - rhs.length; + } + }; - /** - * @param sizeLimit the maximum size of the pool, in bytes - */ + /** @param sizeLimit the maximum size of the pool, in bytes */ public ByteArrayPool(int sizeLimit) { mSizeLimit = sizeLimit; } @@ -85,7 +83,7 @@ public class ByteArrayPool { * one if a pooled one is not available. * * @param len the minimum size, in bytes, of the requested buffer. The returned buffer may be - * larger. + * larger. * @return a byte[] buffer is always returned. */ public synchronized byte[] getBuf(int len) { @@ -121,9 +119,7 @@ public class ByteArrayPool { trim(); } - /** - * Removes buffers from the pool until it is under its size limit. - */ + /** Removes buffers from the pool until it is under its size limit. */ private synchronized void trim() { while (mCurrentSize > mSizeLimit) { byte[] buf = mBuffersByLastUse.remove(0); @@ -131,5 +127,4 @@ public class ByteArrayPool { mCurrentSize -= buf.length; } } - } diff --git a/src/main/java/com/android/volley/toolbox/ClearCacheRequest.java b/src/main/java/com/android/volley/toolbox/ClearCacheRequest.java index a3478bf..856ef80 100644 --- a/src/main/java/com/android/volley/toolbox/ClearCacheRequest.java +++ b/src/main/java/com/android/volley/toolbox/ClearCacheRequest.java @@ -16,26 +16,23 @@ package com.android.volley.toolbox; +import android.os.Handler; +import android.os.Looper; import com.android.volley.Cache; import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.Response; -import android.os.Handler; -import android.os.Looper; - -/** - * A synthetic request used for clearing the cache. - */ +/** A synthetic request used for clearing the cache. */ public class ClearCacheRequest extends Request<Object> { private final Cache mCache; private final Runnable mCallback; /** * Creates a synthetic request for clearing the cache. + * * @param cache Cache to clear - * @param callback Callback to make on the main thread once the cache is clear, - * or null for none + * @param callback Callback to make on the main thread once the cache is clear, or null for none */ public ClearCacheRequest(Cache cache, Runnable callback) { super(Method.GET, null, null); @@ -65,6 +62,5 @@ public class ClearCacheRequest extends Request<Object> { } @Override - protected void deliverResponse(Object response) { - } + protected void deliverResponse(Object response) {} } diff --git a/src/main/java/com/android/volley/toolbox/DiskBasedCache.java b/src/main/java/com/android/volley/toolbox/DiskBasedCache.java index a6cd960..c49588f 100644 --- a/src/main/java/com/android/volley/toolbox/DiskBasedCache.java +++ b/src/main/java/com/android/volley/toolbox/DiskBasedCache.java @@ -17,12 +17,11 @@ package com.android.volley.toolbox; import android.os.SystemClock; +import android.support.annotation.VisibleForTesting; import android.text.TextUtils; - import com.android.volley.Cache; import com.android.volley.Header; import com.android.volley.VolleyLog; - import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; @@ -43,16 +42,15 @@ import java.util.List; import java.util.Map; /** - * Cache implementation that caches files directly onto the hard disk in the specified - * directory. The default disk usage size is 5MB, but is configurable. + * Cache implementation that caches files directly onto the hard disk in the specified directory. + * The default disk usage size is 5MB, but is configurable. * * <p>This cache supports the {@link Entry#allResponseHeaders} headers field. */ public class DiskBasedCache implements Cache { /** Map of the Key, CacheHeader pairs */ - private final Map<String, CacheHeader> mEntries = - new LinkedHashMap<String, CacheHeader>(16, .75f, true); + private final Map<String, CacheHeader> mEntries = new LinkedHashMap<>(16, .75f, true); /** Total amount of space currently used by the cache in bytes. */ private long mTotalSize = 0; @@ -74,6 +72,7 @@ public class DiskBasedCache implements Cache { /** * Constructs an instance of the DiskBasedCache at the specified directory. + * * @param rootDirectory The root directory of the cache. * @param maxCacheSizeInBytes The maximum size of the cache in bytes. */ @@ -83,17 +82,16 @@ public class DiskBasedCache implements Cache { } /** - * Constructs an instance of the DiskBasedCache at the specified directory using - * the default maximum cache size of 5MB. + * Constructs an instance of the DiskBasedCache at the specified directory using the default + * maximum cache size of 5MB. + * * @param rootDirectory The root directory of the cache. */ public DiskBasedCache(File rootDirectory) { this(rootDirectory, DEFAULT_DISK_USAGE_BYTES); } - /** - * Clears the cache. Deletes all cached files from disk. - */ + /** Clears the cache. Deletes all cached files from disk. */ @Override public synchronized void clear() { File[] files = mRootDirectory.listFiles(); @@ -107,9 +105,7 @@ public class DiskBasedCache implements Cache { VolleyLog.d("Cache cleared."); } - /** - * Returns the cache entry with the specified key if it exists, null otherwise. - */ + /** Returns the cache entry with the specified key if it exists, null otherwise. */ @Override public synchronized Entry get(String key) { CacheHeader entry = mEntries.get(key); @@ -119,14 +115,15 @@ public class DiskBasedCache implements Cache { } File file = getFileForKey(key); try { - CountingInputStream cis = new CountingInputStream( - new BufferedInputStream(createInputStream(file)), file.length()); + CountingInputStream cis = + new CountingInputStream( + new BufferedInputStream(createInputStream(file)), file.length()); try { CacheHeader entryOnDisk = CacheHeader.readHeader(cis); if (!TextUtils.equals(key, entryOnDisk.key)) { // File was shared by two keys and now holds data for a different entry! - VolleyLog.d("%s: key=%s, found=%s", - file.getAbsolutePath(), key, entryOnDisk.key); + VolleyLog.d( + "%s: key=%s, found=%s", file.getAbsolutePath(), key, entryOnDisk.key); // Remove key whose contents on disk have been replaced. removeEntry(key); return null; @@ -146,8 +143,8 @@ public class DiskBasedCache implements Cache { } /** - * Initializes the DiskBasedCache by scanning for all files currently in the - * specified root directory. Creates the root directory if necessary. + * Initializes the DiskBasedCache by scanning for all files currently in the specified root + * directory. Creates the root directory if necessary. */ @Override public synchronized void initialize() { @@ -164,8 +161,9 @@ public class DiskBasedCache implements Cache { for (File file : files) { try { long entrySize = file.length(); - CountingInputStream cis = new CountingInputStream( - new BufferedInputStream(createInputStream(file)), entrySize); + CountingInputStream cis = + new CountingInputStream( + new BufferedInputStream(createInputStream(file)), entrySize); try { CacheHeader entry = CacheHeader.readHeader(cis); // NOTE: When this entry was put, its size was recorded as data.length, but @@ -186,6 +184,7 @@ public class DiskBasedCache implements Cache { /** * Invalidates an entry in the cache. + * * @param key Cache key * @param fullExpire True to fully expire the entry, false to soft expire */ @@ -201,9 +200,7 @@ public class DiskBasedCache implements Cache { } } - /** - * Puts the entry with the specified key into the cache. - */ + /** Puts the entry with the specified key into the cache. */ @Override public synchronized void put(String key, Entry entry) { pruneIfNeeded(entry.data.length); @@ -229,21 +226,21 @@ public class DiskBasedCache implements Cache { } } - /** - * Removes the specified key from the cache if it exists. - */ + /** Removes the specified key from the cache if it exists. */ @Override public synchronized void remove(String key) { boolean deleted = getFileForKey(key).delete(); removeEntry(key); if (!deleted) { - VolleyLog.d("Could not delete cache entry for key=%s, filename=%s", + VolleyLog.d( + "Could not delete cache entry for key=%s, filename=%s", key, getFilenameForKey(key)); } } /** * Creates a pseudo-unique filename for the specified cache key. + * * @param key The key to generate a file name for. * @return A pseudo-unique filename. */ @@ -254,15 +251,14 @@ public class DiskBasedCache implements Cache { return localFilename; } - /** - * Returns a file object for the given cache key. - */ + /** Returns a file object for the given cache key. */ public File getFileForKey(String key) { return new File(mRootDirectory, getFilenameForKey(key)); } /** * Prunes the cache to fit the amount of bytes specified. + * * @param neededSpace The amount of bytes we are trying to fit into the cache. */ private void pruneIfNeeded(int neededSpace) { @@ -285,8 +281,9 @@ public class DiskBasedCache implements Cache { if (deleted) { mTotalSize -= e.size; } else { - VolleyLog.d("Could not delete cache entry for key=%s, filename=%s", - e.key, getFilenameForKey(e.key)); + VolleyLog.d( + "Could not delete cache entry for key=%s, filename=%s", + e.key, getFilenameForKey(e.key)); } iterator.remove(); prunedFiles++; @@ -297,13 +294,15 @@ public class DiskBasedCache implements Cache { } if (VolleyLog.DEBUG) { - VolleyLog.v("pruned %d files, %d bytes, %d ms", + VolleyLog.v( + "pruned %d files, %d bytes, %d ms", prunedFiles, (mTotalSize - before), SystemClock.elapsedRealtime() - startTime); } } /** * Puts the entry with the specified key into the cache. + * * @param key The key to identify the entry by. * @param entry The entry to cache. */ @@ -317,9 +316,7 @@ public class DiskBasedCache implements Cache { mEntries.put(key, entry); } - /** - * Removes the entry identified by 'key' from the cache. - */ + /** Removes the entry identified by 'key' from the cache. */ private void removeEntry(String key) { CacheHeader removed = mEntries.remove(key); if (removed != null) { @@ -329,11 +326,12 @@ public class DiskBasedCache implements Cache { /** * Reads length bytes from CountingInputStream into byte array. + * * @param cis input stream * @param length number of bytes to read * @throws IOException if fails to read all bytes */ - //VisibleForTesting + // VisibleForTesting static byte[] streamToBytes(CountingInputStream cis, long length) throws IOException { long maxLength = cis.bytesRemaining(); // Length cannot be negative or greater than bytes remaining, and must not overflow int. @@ -345,23 +343,20 @@ public class DiskBasedCache implements Cache { return bytes; } - //VisibleForTesting + // VisibleForTesting InputStream createInputStream(File file) throws FileNotFoundException { return new FileInputStream(file); } - //VisibleForTesting + // VisibleForTesting OutputStream createOutputStream(File file) throws FileNotFoundException { return new FileOutputStream(file); } - /** - * Handles holding onto the cache headers for an entry. - */ - //VisibleForTesting + /** Handles holding onto the cache headers for an entry. */ + // VisibleForTesting static class CacheHeader { - /** The size of the data identified by this CacheHeader. (This is not - * serialized to disk. */ + /** The size of the data identified by this CacheHeader. (This is not serialized to disk. */ long size; /** The key that identifies the cache entry. */ @@ -385,8 +380,14 @@ public class DiskBasedCache implements Cache { /** Headers from the response resulting in this cache entry. */ final List<Header> allResponseHeaders; - private CacheHeader(String key, String etag, long serverDate, long lastModified, long ttl, - long softTtl, List<Header> allResponseHeaders) { + private CacheHeader( + String key, + String etag, + long serverDate, + long lastModified, + long ttl, + long softTtl, + List<Header> allResponseHeaders) { this.key = key; this.etag = ("".equals(etag)) ? null : etag; this.serverDate = serverDate; @@ -398,11 +399,18 @@ public class DiskBasedCache implements Cache { /** * Instantiates a new CacheHeader object. + * * @param key The key that identifies the cache entry * @param entry The cache entry. */ CacheHeader(String key, Entry entry) { - this(key, entry.etag, entry.serverDate, entry.lastModified, entry.ttl, entry.softTtl, + this( + key, + entry.etag, + entry.serverDate, + entry.lastModified, + entry.ttl, + entry.softTtl, getAllResponseHeaders(entry)); size = entry.data.length; } @@ -419,6 +427,7 @@ public class DiskBasedCache implements Cache { /** * Reads the header from a CountingInputStream and returns a CacheHeader object. + * * @param is The InputStream to read from. * @throws IOException if fails to read header */ @@ -439,9 +448,7 @@ public class DiskBasedCache implements Cache { key, etag, serverDate, lastModified, ttl, softTtl, allResponseHeaders); } - /** - * Creates a cache entry for the specified data. - */ + /** Creates a cache entry for the specified data. */ Entry toCacheEntry(byte[] data) { Entry e = new Entry(); e.data = data; @@ -455,9 +462,7 @@ public class DiskBasedCache implements Cache { return e; } - /** - * Writes the contents of this CacheHeader to the specified OutputStream. - */ + /** Writes the contents of this CacheHeader to the specified OutputStream. */ boolean writeHeader(OutputStream os) { try { writeInt(os, CACHE_MAGIC); @@ -477,7 +482,7 @@ public class DiskBasedCache implements Cache { } } - //VisibleForTesting + @VisibleForTesting static class CountingInputStream extends FilterInputStream { private final long length; private long bytesRead; @@ -505,7 +510,7 @@ public class DiskBasedCache implements Cache { return result; } - //VisibleForTesting + @VisibleForTesting long bytesRead() { return bytesRead; } @@ -525,8 +530,8 @@ public class DiskBasedCache implements Cache { */ /** - * Simple wrapper around {@link InputStream#read()} that throws EOFException - * instead of returning -1. + * Simple wrapper around {@link InputStream#read()} that throws EOFException instead of + * returning -1. */ private static int read(InputStream is) throws IOException { int b = is.read(); @@ -553,14 +558,14 @@ public class DiskBasedCache implements Cache { } static void writeLong(OutputStream os, long n) throws IOException { - os.write((byte)(n >>> 0)); - os.write((byte)(n >>> 8)); - os.write((byte)(n >>> 16)); - os.write((byte)(n >>> 24)); - os.write((byte)(n >>> 32)); - os.write((byte)(n >>> 40)); - os.write((byte)(n >>> 48)); - os.write((byte)(n >>> 56)); + os.write((byte) (n >>> 0)); + os.write((byte) (n >>> 8)); + os.write((byte) (n >>> 16)); + os.write((byte) (n >>> 24)); + os.write((byte) (n >>> 32)); + os.write((byte) (n >>> 40)); + os.write((byte) (n >>> 48)); + os.write((byte) (n >>> 56)); } static long readLong(InputStream is) throws IOException { @@ -602,9 +607,11 @@ public class DiskBasedCache implements Cache { static List<Header> readHeaderList(CountingInputStream cis) throws IOException { int size = readInt(cis); - List<Header> result = (size == 0) - ? Collections.<Header>emptyList() - : new ArrayList<Header>(size); + if (size < 0) { + throw new IOException("readHeaderList size=" + size); + } + List<Header> result = + (size == 0) ? Collections.<Header>emptyList() : new ArrayList<Header>(); for (int i = 0; i < size; i++) { String name = readString(cis).intern(); String value = readString(cis).intern(); @@ -612,5 +619,4 @@ public class DiskBasedCache implements Cache { } return result; } - } diff --git a/src/main/java/com/android/volley/toolbox/HttpClientStack.java b/src/main/java/com/android/volley/toolbox/HttpClientStack.java index 023ee21..be0918a 100644 --- a/src/main/java/com/android/volley/toolbox/HttpClientStack.java +++ b/src/main/java/com/android/volley/toolbox/HttpClientStack.java @@ -19,7 +19,11 @@ package com.android.volley.toolbox; import com.android.volley.AuthFailureError; import com.android.volley.Request; import com.android.volley.Request.Method; - +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; @@ -38,23 +42,17 @@ import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - /** * An HttpStack that performs request over an {@link HttpClient}. * * @deprecated The Apache HTTP library on Android is deprecated. Use {@link HurlStack} or another - * {@link BaseHttpStack} implementation. + * {@link BaseHttpStack} implementation. */ @Deprecated public class HttpClientStack implements HttpStack { protected final HttpClient mClient; - private final static String HEADER_CONTENT_TYPE = "Content-Type"; + private static final String HEADER_CONTENT_TYPE = "Content-Type"; public HttpClientStack(HttpClient client) { mClient = client; @@ -68,7 +66,7 @@ public class HttpClientStack implements HttpStack { @SuppressWarnings("unused") private static List<NameValuePair> getPostParameterPairs(Map<String, String> postParams) { - List<NameValuePair> result = new ArrayList<NameValuePair>(postParams.size()); + List<NameValuePair> result = new ArrayList<>(postParams.size()); for (String key : postParams.keySet()) { result.add(new BasicNameValuePair(key, postParams.get(key))); } @@ -91,64 +89,70 @@ public class HttpClientStack implements HttpStack { return mClient.execute(httpRequest); } - /** - * Creates the appropriate subclass of HttpUriRequest for passed in request. - */ + /** Creates the appropriate subclass of HttpUriRequest for passed in request. */ @SuppressWarnings("deprecation") - /* protected */ static HttpUriRequest createHttpRequest(Request<?> request, - Map<String, String> additionalHeaders) throws AuthFailureError { + /* protected */ static HttpUriRequest createHttpRequest( + Request<?> request, Map<String, String> additionalHeaders) throws AuthFailureError { switch (request.getMethod()) { - case Method.DEPRECATED_GET_OR_POST: { - // This is the deprecated way that needs to be handled for backwards compatibility. - // If the request's post body is null, then the assumption is that the request is - // GET. Otherwise, it is assumed that the request is a POST. - byte[] postBody = request.getPostBody(); - if (postBody != null) { - HttpPost postRequest = new HttpPost(request.getUrl()); - postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType()); - HttpEntity entity; - entity = new ByteArrayEntity(postBody); - postRequest.setEntity(entity); - return postRequest; - } else { - return new HttpGet(request.getUrl()); + case Method.DEPRECATED_GET_OR_POST: + { + // This is the deprecated way that needs to be handled for backwards + // compatibility. + // If the request's post body is null, then the assumption is that the request + // is + // GET. Otherwise, it is assumed that the request is a POST. + byte[] postBody = request.getPostBody(); + if (postBody != null) { + HttpPost postRequest = new HttpPost(request.getUrl()); + postRequest.addHeader( + HEADER_CONTENT_TYPE, request.getPostBodyContentType()); + HttpEntity entity; + entity = new ByteArrayEntity(postBody); + postRequest.setEntity(entity); + return postRequest; + } else { + return new HttpGet(request.getUrl()); + } } - } case Method.GET: return new HttpGet(request.getUrl()); case Method.DELETE: return new HttpDelete(request.getUrl()); - case Method.POST: { - HttpPost postRequest = new HttpPost(request.getUrl()); - postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); - setEntityIfNonEmptyBody(postRequest, request); - return postRequest; - } - case Method.PUT: { - HttpPut putRequest = new HttpPut(request.getUrl()); - putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); - setEntityIfNonEmptyBody(putRequest, request); - return putRequest; - } + case Method.POST: + { + HttpPost postRequest = new HttpPost(request.getUrl()); + postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); + setEntityIfNonEmptyBody(postRequest, request); + return postRequest; + } + case Method.PUT: + { + HttpPut putRequest = new HttpPut(request.getUrl()); + putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); + setEntityIfNonEmptyBody(putRequest, request); + return putRequest; + } case Method.HEAD: return new HttpHead(request.getUrl()); case Method.OPTIONS: return new HttpOptions(request.getUrl()); case Method.TRACE: return new HttpTrace(request.getUrl()); - case Method.PATCH: { - HttpPatch patchRequest = new HttpPatch(request.getUrl()); - patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); - setEntityIfNonEmptyBody(patchRequest, request); - return patchRequest; - } + case Method.PATCH: + { + HttpPatch patchRequest = new HttpPatch(request.getUrl()); + patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); + setEntityIfNonEmptyBody(patchRequest, request); + return patchRequest; + } default: throw new IllegalStateException("Unknown request method."); } } - private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest, - Request<?> request) throws AuthFailureError { + private static void setEntityIfNonEmptyBody( + HttpEntityEnclosingRequestBase httpRequest, Request<?> request) + throws AuthFailureError { byte[] body = request.getBody(); if (body != null) { HttpEntity entity = new ByteArrayEntity(body); @@ -159,7 +163,7 @@ public class HttpClientStack implements HttpStack { /** * Called before the request is executed using the underlying HttpClient. * - * <p>Overwrite in subclasses to augment the request.</p> + * <p>Overwrite in subclasses to augment the request. */ protected void onPrepareRequest(HttpUriRequest request) throws IOException { // Nothing. @@ -170,7 +174,7 @@ public class HttpClientStack implements HttpStack { */ public static final class HttpPatch extends HttpEntityEnclosingRequestBase { - public final static String METHOD_NAME = "PATCH"; + public static final String METHOD_NAME = "PATCH"; public HttpPatch() { super(); @@ -181,9 +185,7 @@ public class HttpClientStack implements HttpStack { setURI(uri); } - /** - * @throws IllegalArgumentException if the uri is invalid. - */ + /** @throws IllegalArgumentException if the uri is invalid. */ public HttpPatch(final String uri) { super(); setURI(URI.create(uri)); @@ -193,6 +195,5 @@ public class HttpClientStack implements HttpStack { public String getMethod() { return METHOD_NAME; } - } } diff --git a/src/main/java/com/android/volley/toolbox/HttpHeaderParser.java b/src/main/java/com/android/volley/toolbox/HttpHeaderParser.java index 211c329..27d1268 100644 --- a/src/main/java/com/android/volley/toolbox/HttpHeaderParser.java +++ b/src/main/java/com/android/volley/toolbox/HttpHeaderParser.java @@ -20,7 +20,6 @@ import com.android.volley.Cache; import com.android.volley.Header; import com.android.volley.NetworkResponse; import com.android.volley.VolleyLog; - import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -31,9 +30,7 @@ import java.util.Map; import java.util.TimeZone; import java.util.TreeMap; -/** - * Utility methods for parsing HTTP headers. - */ +/** Utility methods for parsing HTTP headers. */ public class HttpHeaderParser { static final String HEADER_CONTENT_TYPE = "Content-Type"; @@ -74,7 +71,7 @@ public class HttpHeaderParser { headerValue = headers.get("Cache-Control"); if (headerValue != null) { hasCacheControl = true; - String[] tokens = headerValue.split(","); + String[] tokens = headerValue.split(",", 0); for (int i = 0; i < tokens.length; i++) { String token = tokens[i].trim(); if (token.equals("no-cache") || token.equals("no-store")) { @@ -111,9 +108,7 @@ public class HttpHeaderParser { // is more restrictive. if (hasCacheControl) { softExpire = now + maxAge * 1000; - finalExpire = mustRevalidate - ? softExpire - : softExpire + staleWhileRevalidate * 1000; + finalExpire = mustRevalidate ? softExpire : softExpire + staleWhileRevalidate * 1000; } else if (serverDate > 0 && serverExpires >= serverDate) { // Default semantic for Expire header in HTTP specification is softExpire. softExpire = now + (serverExpires - serverDate); @@ -133,9 +128,7 @@ public class HttpHeaderParser { return entry; } - /** - * Parse date in RFC1123 format, and return its value as epoch - */ + /** Parse date in RFC1123 format, and return its value as epoch */ public static long parseDateAsEpoch(String dateStr) { try { // Parse date in RFC1123 format if this header contains one @@ -153,8 +146,7 @@ public class HttpHeaderParser { } private static SimpleDateFormat newRfc1123Formatter() { - SimpleDateFormat formatter = - new SimpleDateFormat(RFC1123_FORMAT, Locale.US); + SimpleDateFormat formatter = new SimpleDateFormat(RFC1123_FORMAT, Locale.US); formatter.setTimeZone(TimeZone.getTimeZone("GMT")); return formatter; } @@ -164,15 +156,15 @@ public class HttpHeaderParser { * * @param headers An {@link java.util.Map} of headers * @param defaultCharset Charset to return if none can be found - * @return Returns the charset specified in the Content-Type of this header, - * or the defaultCharset if none can be found. + * @return Returns the charset specified in the Content-Type of this header, or the + * defaultCharset if none can be found. */ public static String parseCharset(Map<String, String> headers, String defaultCharset) { String contentType = headers.get(HEADER_CONTENT_TYPE); if (contentType != null) { - String[] params = contentType.split(";"); + String[] params = contentType.split(";", 0); for (int i = 1; i < params.length; i++) { - String[] pair = params[i].trim().split("="); + String[] pair = params[i].trim().split("=", 0); if (pair.length == 2) { if (pair[0].equals("charset")) { return pair[1]; @@ -185,8 +177,8 @@ public class HttpHeaderParser { } /** - * Returns the charset specified in the Content-Type of this header, - * or the HTTP default (ISO-8859-1) if none can be found. + * Returns the charset specified in the Content-Type of this header, or the HTTP default + * (ISO-8859-1) if none can be found. */ public static String parseCharset(Map<String, String> headers) { return parseCharset(headers, DEFAULT_CONTENT_CHARSET); diff --git a/src/main/java/com/android/volley/toolbox/HttpResponse.java b/src/main/java/com/android/volley/toolbox/HttpResponse.java index db719bc..9a9294f 100644 --- a/src/main/java/com/android/volley/toolbox/HttpResponse.java +++ b/src/main/java/com/android/volley/toolbox/HttpResponse.java @@ -16,7 +16,6 @@ package com.android.volley.toolbox; import com.android.volley.Header; - import java.io.InputStream; import java.util.Collections; import java.util.List; @@ -36,7 +35,7 @@ public final class HttpResponse { * @param headers the response headers */ public HttpResponse(int statusCode, List<Header> headers) { - this(statusCode, headers, -1 /* contentLength */, null /* content */); + this(statusCode, headers, /* contentLength= */ -1, /* content= */ null); } /** diff --git a/src/main/java/com/android/volley/toolbox/HttpStack.java b/src/main/java/com/android/volley/toolbox/HttpStack.java index 5d34b44..85179a7 100644 --- a/src/main/java/com/android/volley/toolbox/HttpStack.java +++ b/src/main/java/com/android/volley/toolbox/HttpStack.java @@ -18,11 +18,9 @@ package com.android.volley.toolbox; import com.android.volley.AuthFailureError; import com.android.volley.Request; - -import org.apache.http.HttpResponse; - import java.io.IOException; import java.util.Map; +import org.apache.http.HttpResponse; /** * An HTTP stack abstraction. @@ -37,14 +35,13 @@ public interface HttpStack { * Performs an HTTP request with the given parameters. * * <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise, - * and the Content-Type header is set to request.getPostBodyContentType().</p> + * and the Content-Type header is set to request.getPostBodyContentType(). * * @param request the request to perform - * @param additionalHeaders additional headers to be sent together with - * {@link Request#getHeaders()} + * @param additionalHeaders additional headers to be sent together with {@link + * Request#getHeaders()} * @return the HTTP response */ HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) - throws IOException, AuthFailureError; - + throws IOException, AuthFailureError; } diff --git a/src/main/java/com/android/volley/toolbox/HurlStack.java b/src/main/java/com/android/volley/toolbox/HurlStack.java index a975a71..dd73759 100644 --- a/src/main/java/com/android/volley/toolbox/HurlStack.java +++ b/src/main/java/com/android/volley/toolbox/HurlStack.java @@ -16,12 +16,13 @@ package com.android.volley.toolbox; +import android.support.annotation.VisibleForTesting; import com.android.volley.AuthFailureError; import com.android.volley.Header; import com.android.volley.Request; import com.android.volley.Request.Method; - import java.io.DataOutputStream; +import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; @@ -30,24 +31,19 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSocketFactory; -/** - * An {@link HttpStack} based on {@link HttpURLConnection}. - */ +/** A {@link BaseHttpStack} based on {@link HttpURLConnection}. */ public class HurlStack extends BaseHttpStack { private static final int HTTP_CONTINUE = 100; - /** - * An interface for transforming URLs before use. - */ + /** An interface for transforming URLs before use. */ public interface UrlRewriter { /** - * Returns a URL to use instead of the provided one, or null to indicate - * this URL should not be used at all. + * Returns a URL to use instead of the provided one, or null to indicate this URL should not + * be used at all. */ String rewriteUrl(String originalUrl); } @@ -56,14 +52,12 @@ public class HurlStack extends BaseHttpStack { private final SSLSocketFactory mSslSocketFactory; public HurlStack() { - this(null); + this(/* urlRewriter = */ null); } - /** - * @param urlRewriter Rewriter to use for request URLs - */ + /** @param urlRewriter Rewriter to use for request URLs */ public HurlStack(UrlRewriter urlRewriter) { - this(urlRewriter, null); + this(urlRewriter, /* sslSocketFactory = */ null); } /** @@ -91,27 +85,40 @@ public class HurlStack extends BaseHttpStack { } URL parsedUrl = new URL(url); HttpURLConnection connection = openConnection(parsedUrl, request); - for (String headerName : map.keySet()) { - connection.addRequestProperty(headerName, map.get(headerName)); - } - setConnectionParametersForRequest(connection, request); - // Initialize HttpResponse with data from the HttpURLConnection. - int responseCode = connection.getResponseCode(); - if (responseCode == -1) { - // -1 is returned by getResponseCode() if the response code could not be retrieved. - // Signal to the caller that something was wrong with the connection. - throw new IOException("Could not retrieve response code from HttpUrlConnection."); - } + boolean keepConnectionOpen = false; + try { + for (String headerName : map.keySet()) { + connection.addRequestProperty(headerName, map.get(headerName)); + } + setConnectionParametersForRequest(connection, request); + // Initialize HttpResponse with data from the HttpURLConnection. + int responseCode = connection.getResponseCode(); + if (responseCode == -1) { + // -1 is returned by getResponseCode() if the response code could not be retrieved. + // Signal to the caller that something was wrong with the connection. + throw new IOException("Could not retrieve response code from HttpUrlConnection."); + } - if (!hasResponseBody(request.getMethod(), responseCode)) { - return new HttpResponse(responseCode, convertHeaders(connection.getHeaderFields())); - } + if (!hasResponseBody(request.getMethod(), responseCode)) { + return new HttpResponse(responseCode, convertHeaders(connection.getHeaderFields())); + } - return new HttpResponse(responseCode, convertHeaders(connection.getHeaderFields()), - connection.getContentLength(), inputStreamFromConnection(connection)); + // Need to keep the connection open until the stream is consumed by the caller. Wrap the + // stream such that close() will disconnect the connection. + keepConnectionOpen = true; + return new HttpResponse( + responseCode, + convertHeaders(connection.getHeaderFields()), + connection.getContentLength(), + new UrlConnectionInputStream(connection)); + } finally { + if (!keepConnectionOpen) { + connection.disconnect(); + } + } } - // VisibleForTesting + @VisibleForTesting static List<Header> convertHeaders(Map<String, List<String>> responseHeaders) { List<Header> headerList = new ArrayList<>(responseHeaders.size()); for (Map.Entry<String, List<String>> entry : responseHeaders.entrySet()) { @@ -128,6 +135,7 @@ public class HurlStack extends BaseHttpStack { /** * Checks if a response message contains a body. + * * @see <a href="https://tools.ietf.org/html/rfc7230#section-3.3">RFC 7230 section 3.3</a> * @param requestMethod request method * @param responseCode response status code @@ -135,13 +143,33 @@ public class HurlStack extends BaseHttpStack { */ private static boolean hasResponseBody(int requestMethod, int responseCode) { return requestMethod != Request.Method.HEAD - && !(HTTP_CONTINUE <= responseCode && responseCode < HttpURLConnection.HTTP_OK) - && responseCode != HttpURLConnection.HTTP_NO_CONTENT - && responseCode != HttpURLConnection.HTTP_NOT_MODIFIED; + && !(HTTP_CONTINUE <= responseCode && responseCode < HttpURLConnection.HTTP_OK) + && responseCode != HttpURLConnection.HTTP_NO_CONTENT + && responseCode != HttpURLConnection.HTTP_NOT_MODIFIED; + } + + /** + * Wrapper for a {@link HttpURLConnection}'s InputStream which disconnects the connection on + * stream close. + */ + static class UrlConnectionInputStream extends FilterInputStream { + private final HttpURLConnection mConnection; + + UrlConnectionInputStream(HttpURLConnection connection) { + super(inputStreamFromConnection(connection)); + mConnection = connection; + } + + @Override + public void close() throws IOException { + super.close(); + mConnection.disconnect(); + } } /** * Initializes an {@link InputStream} from the given {@link HttpURLConnection}. + * * @param connection * @return an HttpEntity populated with data from <code>connection</code>. */ @@ -155,9 +183,7 @@ public class HurlStack extends BaseHttpStack { return inputStream; } - /** - * Create an {@link HttpURLConnection} for the specified {@code url}. - */ + /** Create an {@link HttpURLConnection} for the specified {@code url}. */ protected HttpURLConnection createConnection(URL url) throws IOException { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); @@ -171,6 +197,7 @@ public class HurlStack extends BaseHttpStack { /** * Opens an {@link HttpURLConnection} with parameters. + * * @param url * @return an open connection * @throws IOException @@ -186,15 +213,15 @@ public class HurlStack extends BaseHttpStack { // use caller-provided custom SslSocketFactory, if any, for HTTPS if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) { - ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory); + ((HttpsURLConnection) connection).setSSLSocketFactory(mSslSocketFactory); } return connection; } @SuppressWarnings("deprecation") - /* package */ static void setConnectionParametersForRequest(HttpURLConnection connection, - Request<?> request) throws IOException, AuthFailureError { + /* package */ static void setConnectionParametersForRequest( + HttpURLConnection connection, Request<?> request) throws IOException, AuthFailureError { switch (request.getMethod()) { case Method.DEPRECATED_GET_OR_POST: // This is the deprecated way that needs to be handled for backwards compatibility. diff --git a/src/main/java/com/android/volley/toolbox/ImageLoader.java b/src/main/java/com/android/volley/toolbox/ImageLoader.java index 33a119b..076c212 100644 --- a/src/main/java/com/android/volley/toolbox/ImageLoader.java +++ b/src/main/java/com/android/volley/toolbox/ImageLoader.java @@ -1,16 +1,14 @@ -/** +/* * Copyright (C) 2013 The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ package com.android.volley.toolbox; @@ -19,25 +17,27 @@ import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.os.Handler; import android.os.Looper; +import android.support.annotation.MainThread; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response.ErrorListener; import com.android.volley.Response.Listener; +import com.android.volley.ResponseDelivery; import com.android.volley.VolleyError; - +import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; +import java.util.List; /** * Helper that handles loading and caching images from remote URLs. * - * The simple way to use this class is to call {@link ImageLoader#get(String, ImageListener)} - * and to pass in the default image listener provided by - * {@link ImageLoader#getImageListener(ImageView, int, int)}. Note that all function calls to - * this class must be made from the main thead, and all responses will be delivered to the main - * thread as well. + * <p>The simple way to use this class is to call {@link ImageLoader#get(String, ImageListener)} and + * to pass in the default image listener provided by {@link ImageLoader#getImageListener(ImageView, + * int, int)}. Note that all function calls to this class must be made from the main thread, and all + * responses will be delivered to the main thread as well. Custom {@link ResponseDelivery}s which + * don't use the main thread are not supported. */ public class ImageLoader { /** RequestQueue for dispatching ImageRequests onto. */ @@ -50,15 +50,13 @@ public class ImageLoader { private final ImageCache mCache; /** - * HashMap of Cache keys -> BatchedImageRequest used to track in-flight requests so - * that we can coalesce multiple requests to the same URL into a single network request. + * HashMap of Cache keys -> BatchedImageRequest used to track in-flight requests so that we can + * coalesce multiple requests to the same URL into a single network request. */ - private final HashMap<String, BatchedImageRequest> mInFlightRequests = - new HashMap<String, BatchedImageRequest>(); + private final HashMap<String, BatchedImageRequest> mInFlightRequests = new HashMap<>(); /** HashMap of the currently pending responses (waiting to be delivered). */ - private final HashMap<String, BatchedImageRequest> mBatchedResponses = - new HashMap<String, BatchedImageRequest>(); + private final HashMap<String, BatchedImageRequest> mBatchedResponses = new HashMap<>(); /** Handler to the main thread. */ private final Handler mHandler = new Handler(Looper.getMainLooper()); @@ -67,17 +65,19 @@ public class ImageLoader { private Runnable mRunnable; /** - * Simple cache adapter interface. If provided to the ImageLoader, it - * will be used as an L1 cache before dispatch to Volley. Implementations - * must not block. Implementation with an LruCache is recommended. + * Simple cache adapter interface. If provided to the ImageLoader, it will be used as an L1 + * cache before dispatch to Volley. Implementations must not block. Implementation with an + * LruCache is recommended. */ public interface ImageCache { Bitmap getBitmap(String url); + void putBitmap(String url, Bitmap bitmap); } /** * Constructs a new ImageLoader. + * * @param queue The RequestQueue to use for making image requests. * @param imageCache The cache to use as an L1 cache. */ @@ -87,15 +87,16 @@ public class ImageLoader { } /** - * The default implementation of ImageListener which handles basic functionality - * of showing a default image until the network response is received, at which point - * it will switch to either the actual image or the error image. + * The default implementation of ImageListener which handles basic functionality of showing a + * default image until the network response is received, at which point it will switch to either + * the actual image or the error image. + * * @param view The imageView that the listener is associated with. * @param defaultImageResId Default image resource ID to use, or 0 if it doesn't exist. * @param errorImageResId Error image resource ID to use, or 0 if it doesn't exist. */ - public static ImageListener getImageListener(final ImageView view, - final int defaultImageResId, final int errorImageResId) { + public static ImageListener getImageListener( + final ImageView view, final int defaultImageResId, final int errorImageResId) { return new ImageListener() { @Override public void onErrorResponse(VolleyError error) { @@ -118,32 +119,30 @@ public class ImageLoader { /** * Interface for the response handlers on image requests. * - * The call flow is this: - * 1. Upon being attached to a request, onResponse(response, true) will - * be invoked to reflect any cached data that was already available. If the - * data was available, response.getBitmap() will be non-null. + * <p>The call flow is this: 1. Upon being attached to a request, onResponse(response, true) + * will be invoked to reflect any cached data that was already available. If the data was + * available, response.getBitmap() will be non-null. * - * 2. After a network response returns, only one of the following cases will happen: - * - onResponse(response, false) will be called if the image was loaded. - * or - * - onErrorResponse will be called if there was an error loading the image. + * <p>2. After a network response returns, only one of the following cases will happen: - + * onResponse(response, false) will be called if the image was loaded. or - onErrorResponse will + * be called if there was an error loading the image. */ public interface ImageListener extends ErrorListener { /** * Listens for non-error changes to the loading of the image request. * - * @param response Holds all information pertaining to the request, as well - * as the bitmap (if it is loaded). - * @param isImmediate True if this was called during ImageLoader.get() variants. - * This can be used to differentiate between a cached image loading and a network - * image loading in order to, for example, run an animation to fade in network loaded - * images. + * @param response Holds all information pertaining to the request, as well as the bitmap + * (if it is loaded). + * @param isImmediate True if this was called during ImageLoader.get() variants. This can be + * used to differentiate between a cached image loading and a network image loading in + * order to, for example, run an animation to fade in network loaded images. */ void onResponse(ImageContainer response, boolean isImmediate); } /** * Checks if the item is available in the cache. + * * @param requestUrl The url of the remote image * @param maxWidth The maximum width of the returned image. * @param maxHeight The maximum height of the returned image. @@ -156,14 +155,17 @@ public class ImageLoader { /** * Checks if the item is available in the cache. * + * <p>Must be called from the main thread. + * * @param requestUrl The url of the remote image - * @param maxWidth The maximum width of the returned image. - * @param maxHeight The maximum height of the returned image. - * @param scaleType The scaleType of the imageView. + * @param maxWidth The maximum width of the returned image. + * @param maxHeight The maximum height of the returned image. + * @param scaleType The scaleType of the imageView. * @return True if the item exists in cache, false otherwise. */ + @MainThread public boolean isCached(String requestUrl, int maxWidth, int maxHeight, ScaleType scaleType) { - throwIfNotOnMainThread(); + Threads.throwIfNotOnMainThread(); String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType); return mCache.getBitmap(cacheKey) != null; @@ -172,43 +174,50 @@ public class ImageLoader { /** * Returns an ImageContainer for the requested URL. * - * The ImageContainer will contain either the specified default bitmap or the loaded bitmap. - * If the default was returned, the {@link ImageLoader} will be invoked when the - * request is fulfilled. + * <p>The ImageContainer will contain either the specified default bitmap or the loaded bitmap. + * If the default was returned, the {@link ImageLoader} will be invoked when the request is + * fulfilled. * * @param requestUrl The URL of the image to be loaded. */ public ImageContainer get(String requestUrl, final ImageListener listener) { - return get(requestUrl, listener, 0, 0); + return get(requestUrl, listener, /* maxWidth= */ 0, /* maxHeight= */ 0); } /** - * Equivalent to calling {@link #get(String, ImageListener, int, int, ScaleType)} with - * {@code Scaletype == ScaleType.CENTER_INSIDE}. + * Equivalent to calling {@link #get(String, ImageListener, int, int, ScaleType)} with {@code + * Scaletype == ScaleType.CENTER_INSIDE}. */ - public ImageContainer get(String requestUrl, ImageListener imageListener, - int maxWidth, int maxHeight) { + public ImageContainer get( + String requestUrl, ImageListener imageListener, int maxWidth, int maxHeight) { return get(requestUrl, imageListener, maxWidth, maxHeight, ScaleType.CENTER_INSIDE); } /** - * Issues a bitmap request with the given URL if that image is not available - * in the cache, and returns a bitmap container that contains all of the data - * relating to the request (as well as the default image if the requested - * image is not available). + * Issues a bitmap request with the given URL if that image is not available in the cache, and + * returns a bitmap container that contains all of the data relating to the request (as well as + * the default image if the requested image is not available). + * + * <p>Must be called from the main thread. + * * @param requestUrl The url of the remote image * @param imageListener The listener to call when the remote image is loaded * @param maxWidth The maximum width of the returned image. * @param maxHeight The maximum height of the returned image. * @param scaleType The ImageViews ScaleType used to calculate the needed image size. - * @return A container object that contains all of the properties of the request, as well as - * the currently available image (default if remote is not loaded). + * @return A container object that contains all of the properties of the request, as well as the + * currently available image (default if remote is not loaded). */ - public ImageContainer get(String requestUrl, ImageListener imageListener, - int maxWidth, int maxHeight, ScaleType scaleType) { + @MainThread + public ImageContainer get( + String requestUrl, + ImageListener imageListener, + int maxWidth, + int maxHeight, + ScaleType scaleType) { // only fulfill requests that were initiated from the main thread. - throwIfNotOnMainThread(); + Threads.throwIfNotOnMainThread(); final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType); @@ -216,7 +225,9 @@ public class ImageLoader { Bitmap cachedBitmap = mCache.getBitmap(cacheKey); if (cachedBitmap != null) { // Return the cached bitmap. - ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null); + ImageContainer container = + new ImageContainer( + cachedBitmap, requestUrl, /* cacheKey= */ null, /* listener= */ null); imageListener.onResponse(container, true); return container; } @@ -238,33 +249,44 @@ public class ImageLoader { // The request is not already in flight. Send the new request to the network and // track it. - Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType, - cacheKey); + Request<Bitmap> newRequest = + makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType, cacheKey); mRequestQueue.add(newRequest); - mInFlightRequests.put(cacheKey, - new BatchedImageRequest(newRequest, imageContainer)); + mInFlightRequests.put(cacheKey, new BatchedImageRequest(newRequest, imageContainer)); return imageContainer; } - protected Request<Bitmap> makeImageRequest(String requestUrl, int maxWidth, int maxHeight, - ScaleType scaleType, final String cacheKey) { - return new ImageRequest(requestUrl, new Listener<Bitmap>() { - @Override - public void onResponse(Bitmap response) { - onGetImageSuccess(cacheKey, response); - } - }, maxWidth, maxHeight, scaleType, Config.RGB_565, new ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - onGetImageError(cacheKey, error); - } - }); + protected Request<Bitmap> makeImageRequest( + String requestUrl, + int maxWidth, + int maxHeight, + ScaleType scaleType, + final String cacheKey) { + return new ImageRequest( + requestUrl, + new Listener<Bitmap>() { + @Override + public void onResponse(Bitmap response) { + onGetImageSuccess(cacheKey, response); + } + }, + maxWidth, + maxHeight, + scaleType, + Config.RGB_565, + new ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + onGetImageError(cacheKey, error); + } + }); } /** * Sets the amount of time to wait after the first response arrives before delivering all * responses. Batching can be disabled entirely by passing in 0. + * * @param newBatchedResponseDelayMs The time in milliseconds to wait. */ public void setBatchedResponseDelay(int newBatchedResponseDelayMs) { @@ -273,6 +295,7 @@ public class ImageLoader { /** * Handler for when an image was successfully loaded. + * * @param cacheKey The cache key that is associated with the image request. * @param response The bitmap that was returned from the network. */ @@ -294,6 +317,7 @@ public class ImageLoader { /** * Handler for when an image failed to load. + * * @param cacheKey The cache key that is associated with the image request. */ protected void onGetImageError(String cacheKey, VolleyError error) { @@ -310,13 +334,11 @@ public class ImageLoader { } } - /** - * Container object for all of the data surrounding an image request. - */ + /** Container object for all of the data surrounding an image request. */ public class ImageContainer { /** - * The most relevant bitmap for the container. If the image was in cache, the - * Holder to use for the final bitmap (the one that pairs to the requested URL). + * The most relevant bitmap for the container. If the image was in cache, the Holder to use + * for the final bitmap (the one that pairs to the requested URL). */ private Bitmap mBitmap; @@ -330,12 +352,13 @@ public class ImageLoader { /** * Constructs a BitmapContainer object. + * * @param bitmap The final bitmap (if it exists). * @param requestUrl The requested URL for this container. * @param cacheKey The cache key that identifies the requested URL for this container. */ - public ImageContainer(Bitmap bitmap, String requestUrl, - String cacheKey, ImageListener listener) { + public ImageContainer( + Bitmap bitmap, String requestUrl, String cacheKey, ImageListener listener) { mBitmap = bitmap; mRequestUrl = requestUrl; mCacheKey = cacheKey; @@ -344,8 +367,13 @@ public class ImageLoader { /** * Releases interest in the in-flight request (and cancels it if no one else is listening). + * + * <p>Must be called from the main thread. */ + @MainThread public void cancelRequest() { + Threads.throwIfNotOnMainThread(); + if (mListener == null) { return; } @@ -375,9 +403,7 @@ public class ImageLoader { return mBitmap; } - /** - * Returns the requested URL for this container. - */ + /** Returns the requested URL for this container. */ public String getRequestUrl() { return mRequestUrl; } @@ -387,7 +413,7 @@ public class ImageLoader { * Wrapper class used to map a Request to the set of active ImageContainer objects that are * interested in its results. */ - private class BatchedImageRequest { + private static class BatchedImageRequest { /** The request being tracked */ private final Request<?> mRequest; @@ -398,10 +424,11 @@ public class ImageLoader { private VolleyError mError; /** List of all of the active ImageContainers that are interested in the request */ - private final LinkedList<ImageContainer> mContainers = new LinkedList<ImageContainer>(); + private final List<ImageContainer> mContainers = new ArrayList<>(); /** * Constructs a new BatchedImageRequest object + * * @param request The request being tracked * @param container The ImageContainer of the person who initiated the request. */ @@ -410,31 +437,28 @@ public class ImageLoader { mContainers.add(container); } - /** - * Set the error for this response - */ + /** Set the error for this response */ public void setError(VolleyError error) { mError = error; } - /** - * Get the error for this response - */ + /** Get the error for this response */ public VolleyError getError() { return mError; } /** - * Adds another ImageContainer to the list of those interested in the results of - * the request. + * Adds another ImageContainer to the list of those interested in the results of the + * request. */ public void addContainer(ImageContainer container) { mContainers.add(container); } /** - * Detatches the bitmap container from the request and cancels the request if no one is - * left listening. + * Detaches the bitmap container from the request and cancels the request if no one is left + * listening. + * * @param container The container to remove from the list * @return True if the request was canceled, false otherwise. */ @@ -450,6 +474,7 @@ public class ImageLoader { /** * Starts the runnable for batched delivery of responses if it is not already started. + * * @param cacheKey The cacheKey of the response being delivered. * @param request The BatchedImageRequest to be delivered. */ @@ -458,50 +483,54 @@ public class ImageLoader { // If we don't already have a batch delivery runnable in flight, make a new one. // Note that this will be used to deliver responses to all callers in mBatchedResponses. if (mRunnable == null) { - mRunnable = new Runnable() { - @Override - public void run() { - for (BatchedImageRequest bir : mBatchedResponses.values()) { - for (ImageContainer container : bir.mContainers) { - // If one of the callers in the batched request canceled the request - // after the response was received but before it was delivered, - // skip them. - if (container.mListener == null) { - continue; - } - if (bir.getError() == null) { - container.mBitmap = bir.mResponseBitmap; - container.mListener.onResponse(container, false); - } else { - container.mListener.onErrorResponse(bir.getError()); + mRunnable = + new Runnable() { + @Override + public void run() { + for (BatchedImageRequest bir : mBatchedResponses.values()) { + for (ImageContainer container : bir.mContainers) { + // If one of the callers in the batched request canceled the + // request + // after the response was received but before it was delivered, + // skip them. + if (container.mListener == null) { + continue; + } + if (bir.getError() == null) { + container.mBitmap = bir.mResponseBitmap; + container.mListener.onResponse(container, false); + } else { + container.mListener.onErrorResponse(bir.getError()); + } + } } + mBatchedResponses.clear(); + mRunnable = null; } - } - mBatchedResponses.clear(); - mRunnable = null; - } - - }; + }; // Post the runnable. mHandler.postDelayed(mRunnable, mBatchResponseDelayMs); } } - private void throwIfNotOnMainThread() { - if (Looper.myLooper() != Looper.getMainLooper()) { - throw new IllegalStateException("ImageLoader must be invoked from the main thread."); - } - } /** * Creates a cache key for use with the L1 cache. + * * @param url The URL of the request. * @param maxWidth The max-width of the output. * @param maxHeight The max-height of the output. * @param scaleType The scaleType of the imageView. */ - private static String getCacheKey(String url, int maxWidth, int maxHeight, ScaleType scaleType) { - return new StringBuilder(url.length() + 12).append("#W").append(maxWidth) - .append("#H").append(maxHeight).append("#S").append(scaleType.ordinal()).append(url) + private static String getCacheKey( + String url, int maxWidth, int maxHeight, ScaleType scaleType) { + return new StringBuilder(url.length() + 12) + .append("#W") + .append(maxWidth) + .append("#H") + .append(maxHeight) + .append("#S") + .append(scaleType.ordinal()) + .append(url) .toString(); } } diff --git a/src/main/java/com/android/volley/toolbox/ImageRequest.java b/src/main/java/com/android/volley/toolbox/ImageRequest.java index 1db7e35..c804267 100644 --- a/src/main/java/com/android/volley/toolbox/ImageRequest.java +++ b/src/main/java/com/android/volley/toolbox/ImageRequest.java @@ -19,8 +19,9 @@ package com.android.volley.toolbox; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; +import android.support.annotation.GuardedBy; +import android.support.annotation.VisibleForTesting; import android.widget.ImageView.ScaleType; - import com.android.volley.DefaultRetryPolicy; import com.android.volley.NetworkResponse; import com.android.volley.ParseError; @@ -28,10 +29,7 @@ import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyLog; -/** - * A canned request for getting an image at a given URL and calling - * back with a decoded Bitmap. - */ +/** A canned request for getting an image at a given URL and calling back with a decoded Bitmap. */ public class ImageRequest extends Request<Bitmap> { /** Socket timeout in milliseconds for image requests */ public static final int DEFAULT_IMAGE_TIMEOUT_MS = 1000; @@ -45,8 +43,9 @@ public class ImageRequest extends Request<Bitmap> { /** Lock to guard mListener as it is cleared on cancel() and read on delivery. */ private final Object mLock = new Object(); - // @GuardedBy("mLock") + @GuardedBy("mLock") private Response.Listener<Bitmap> mListener; + private final Config mDecodeConfig; private final int mMaxWidth; private final int mMaxHeight; @@ -56,28 +55,34 @@ public class ImageRequest extends Request<Bitmap> { private static final Object sDecodeLock = new Object(); /** - * Creates a new image request, decoding to a maximum specified width and - * height. If both width and height are zero, the image will be decoded to - * its natural size. If one of the two is nonzero, that dimension will be - * clamped and the other one will be set to preserve the image's aspect - * ratio. If both width and height are nonzero, the image will be decoded to - * be fit in the rectangle of dimensions width x height while keeping its - * aspect ratio. + * Creates a new image request, decoding to a maximum specified width and height. If both width + * and height are zero, the image will be decoded to its natural size. If one of the two is + * nonzero, that dimension will be clamped and the other one will be set to preserve the image's + * aspect ratio. If both width and height are nonzero, the image will be decoded to be fit in + * the rectangle of dimensions width x height while keeping its aspect ratio. * * @param url URL of the image * @param listener Listener to receive the decoded bitmap * @param maxWidth Maximum width to decode this bitmap to, or zero for none - * @param maxHeight Maximum height to decode this bitmap to, or zero for - * none + * @param maxHeight Maximum height to decode this bitmap to, or zero for none * @param scaleType The ImageViews ScaleType used to calculate the needed image size. * @param decodeConfig Format to decode the bitmap to * @param errorListener Error listener, or null to ignore errors */ - public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight, - ScaleType scaleType, Config decodeConfig, Response.ErrorListener errorListener) { + public ImageRequest( + String url, + Response.Listener<Bitmap> listener, + int maxWidth, + int maxHeight, + ScaleType scaleType, + Config decodeConfig, + Response.ErrorListener errorListener) { super(Method.GET, url, errorListener); - setRetryPolicy(new DefaultRetryPolicy(DEFAULT_IMAGE_TIMEOUT_MS, DEFAULT_IMAGE_MAX_RETRIES, - DEFAULT_IMAGE_BACKOFF_MULT)); + setRetryPolicy( + new DefaultRetryPolicy( + DEFAULT_IMAGE_TIMEOUT_MS, + DEFAULT_IMAGE_MAX_RETRIES, + DEFAULT_IMAGE_BACKOFF_MULT)); mListener = listener; mDecodeConfig = decodeConfig; mMaxWidth = maxWidth; @@ -86,15 +91,27 @@ public class ImageRequest extends Request<Bitmap> { } /** - * For API compatibility with the pre-ScaleType variant of the constructor. Equivalent to - * the normal constructor with {@code ScaleType.CENTER_INSIDE}. + * For API compatibility with the pre-ScaleType variant of the constructor. Equivalent to the + * normal constructor with {@code ScaleType.CENTER_INSIDE}. */ @Deprecated - public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight, - Config decodeConfig, Response.ErrorListener errorListener) { - this(url, listener, maxWidth, maxHeight, - ScaleType.CENTER_INSIDE, decodeConfig, errorListener); + public ImageRequest( + String url, + Response.Listener<Bitmap> listener, + int maxWidth, + int maxHeight, + Config decodeConfig, + Response.ErrorListener errorListener) { + this( + url, + listener, + maxWidth, + maxHeight, + ScaleType.CENTER_INSIDE, + decodeConfig, + errorListener); } + @Override public Priority getPriority() { return Priority.LOW; @@ -103,17 +120,20 @@ public class ImageRequest extends Request<Bitmap> { /** * Scales one side of a rectangle to fit aspect ratio. * - * @param maxPrimary Maximum size of the primary dimension (i.e. width for - * max width), or zero to maintain aspect ratio with secondary - * dimension - * @param maxSecondary Maximum size of the secondary dimension, or zero to - * maintain aspect ratio with primary dimension + * @param maxPrimary Maximum size of the primary dimension (i.e. width for max width), or zero + * to maintain aspect ratio with secondary dimension + * @param maxSecondary Maximum size of the secondary dimension, or zero to maintain aspect ratio + * with primary dimension * @param actualPrimary Actual size of the primary dimension * @param actualSecondary Actual size of the secondary dimension * @param scaleType The ScaleType used to calculate the needed image size. */ - private static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary, - int actualSecondary, ScaleType scaleType) { + private static int getResizedDimension( + int maxPrimary, + int maxSecondary, + int actualPrimary, + int actualSecondary, + ScaleType scaleType) { // If no dominant value at all, just return the actual. if ((maxPrimary == 0) && (maxSecondary == 0)) { @@ -168,9 +188,7 @@ public class ImageRequest extends Request<Bitmap> { } } - /** - * The real guts of parseNetworkResponse. Broken out for readability. - */ + /** The real guts of parseNetworkResponse. Broken out for readability. */ private Response<Bitmap> doParse(NetworkResponse response) { byte[] data = response.data; BitmapFactory.Options decodeOptions = new BitmapFactory.Options(); @@ -186,25 +204,26 @@ public class ImageRequest extends Request<Bitmap> { int actualHeight = decodeOptions.outHeight; // Then compute the dimensions we would ideally like to decode to. - int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight, - actualWidth, actualHeight, mScaleType); - int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth, - actualHeight, actualWidth, mScaleType); + int desiredWidth = + getResizedDimension( + mMaxWidth, mMaxHeight, actualWidth, actualHeight, mScaleType); + int desiredHeight = + getResizedDimension( + mMaxHeight, mMaxWidth, actualHeight, actualWidth, mScaleType); // Decode to the nearest power of two scaling factor. decodeOptions.inJustDecodeBounds = false; // TODO(ficus): Do we need this or is it okay since API 8 doesn't support it? // decodeOptions.inPreferQualityOverSpeed = PREFER_QUALITY_OVER_SPEED; decodeOptions.inSampleSize = - findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight); - Bitmap tempBitmap = - BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); + findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight); + Bitmap tempBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); // If necessary, scale down to the maximal acceptable size. - if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth || - tempBitmap.getHeight() > desiredHeight)) { - bitmap = Bitmap.createScaledBitmap(tempBitmap, - desiredWidth, desiredHeight, true); + if (tempBitmap != null + && (tempBitmap.getWidth() > desiredWidth + || tempBitmap.getHeight() > desiredHeight)) { + bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth, desiredHeight, true); tempBitmap.recycle(); } else { bitmap = tempBitmap; @@ -238,15 +257,15 @@ public class ImageRequest extends Request<Bitmap> { } /** - * Returns the largest power-of-two divisor for use in downscaling a bitmap - * that will not result in the scaling past the desired dimensions. + * Returns the largest power-of-two divisor for use in downscaling a bitmap that will not result + * in the scaling past the desired dimensions. * * @param actualWidth Actual width of the bitmap * @param actualHeight Actual height of the bitmap * @param desiredWidth Desired width of the bitmap * @param desiredHeight Desired height of the bitmap */ - // Visible for testing. + @VisibleForTesting static int findBestSampleSize( int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) { double wr = (double) actualWidth / desiredWidth; diff --git a/src/main/java/com/android/volley/toolbox/JsonArrayRequest.java b/src/main/java/com/android/volley/toolbox/JsonArrayRequest.java index ba35d26..757c7f9 100644 --- a/src/main/java/com/android/volley/toolbox/JsonArrayRequest.java +++ b/src/main/java/com/android/volley/toolbox/JsonArrayRequest.java @@ -21,19 +21,16 @@ import com.android.volley.ParseError; import com.android.volley.Response; import com.android.volley.Response.ErrorListener; import com.android.volley.Response.Listener; - +import java.io.UnsupportedEncodingException; import org.json.JSONArray; import org.json.JSONException; -import java.io.UnsupportedEncodingException; - -/** - * A request for retrieving a {@link JSONArray} response body at a given URL. - */ +/** A request for retrieving a {@link JSONArray} response body at a given URL. */ public class JsonArrayRequest extends JsonRequest<JSONArray> { /** * Creates a new request. + * * @param url URL to fetch the JSON from * @param listener Listener to receive the JSON response * @param errorListener Error listener, or null to ignore errors. @@ -44,26 +41,37 @@ public class JsonArrayRequest extends JsonRequest<JSONArray> { /** * Creates a new request. + * * @param method the HTTP method to use * @param url URL to fetch the JSON from * @param jsonRequest A {@link JSONArray} to post with the request. Null is allowed and - * indicates no parameters will be posted along with request. + * indicates no parameters will be posted along with request. * @param listener Listener to receive the JSON response * @param errorListener Error listener, or null to ignore errors. */ - public JsonArrayRequest(int method, String url, JSONArray jsonRequest, - Listener<JSONArray> listener, ErrorListener errorListener) { - super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, + public JsonArrayRequest( + int method, + String url, + JSONArray jsonRequest, + Listener<JSONArray> listener, + ErrorListener errorListener) { + super( + method, + url, + (jsonRequest == null) ? null : jsonRequest.toString(), + listener, errorListener); } @Override protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) { try { - String jsonString = new String(response.data, - HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)); - return Response.success(new JSONArray(jsonString), - HttpHeaderParser.parseCacheHeaders(response)); + String jsonString = + new String( + response.data, + HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)); + return Response.success( + new JSONArray(jsonString), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JSONException je) { diff --git a/src/main/java/com/android/volley/toolbox/JsonObjectRequest.java b/src/main/java/com/android/volley/toolbox/JsonObjectRequest.java index 2991898..e9dc3d7 100644 --- a/src/main/java/com/android/volley/toolbox/JsonObjectRequest.java +++ b/src/main/java/com/android/volley/toolbox/JsonObjectRequest.java @@ -21,12 +21,10 @@ import com.android.volley.ParseError; import com.android.volley.Response; import com.android.volley.Response.ErrorListener; import com.android.volley.Response.Listener; - +import java.io.UnsupportedEncodingException; import org.json.JSONException; import org.json.JSONObject; -import java.io.UnsupportedEncodingException; - /** * A request for retrieving a {@link JSONObject} response body at a given URL, allowing for an * optional {@link JSONObject} to be passed in as part of the request body. @@ -35,38 +33,56 @@ public class JsonObjectRequest extends JsonRequest<JSONObject> { /** * Creates a new request. + * * @param method the HTTP method to use * @param url URL to fetch the JSON from * @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and - * indicates no parameters will be posted along with request. + * indicates no parameters will be posted along with request. * @param listener Listener to receive the JSON response * @param errorListener Error listener, or null to ignore errors. */ - public JsonObjectRequest(int method, String url, JSONObject jsonRequest, - Listener<JSONObject> listener, ErrorListener errorListener) { - super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, - errorListener); + public JsonObjectRequest( + int method, + String url, + JSONObject jsonRequest, + Listener<JSONObject> listener, + ErrorListener errorListener) { + super( + method, + url, + (jsonRequest == null) ? null : jsonRequest.toString(), + listener, + errorListener); } /** - * Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is - * <code>null</code>, <code>POST</code> otherwise. + * Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is <code>null + * </code> , <code>POST</code> otherwise. * * @see #JsonObjectRequest(int, String, JSONObject, Listener, ErrorListener) */ - public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener, + public JsonObjectRequest( + String url, + JSONObject jsonRequest, + Listener<JSONObject> listener, ErrorListener errorListener) { - this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest, - listener, errorListener); + this( + jsonRequest == null ? Method.GET : Method.POST, + url, + jsonRequest, + listener, + errorListener); } @Override protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) { try { - String jsonString = new String(response.data, - HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)); - return Response.success(new JSONObject(jsonString), - HttpHeaderParser.parseCacheHeaders(response)); + String jsonString = + new String( + response.data, + HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)); + return Response.success( + new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JSONException je) { diff --git a/src/main/java/com/android/volley/toolbox/JsonRequest.java b/src/main/java/com/android/volley/toolbox/JsonRequest.java index f291076..fd395dd 100644 --- a/src/main/java/com/android/volley/toolbox/JsonRequest.java +++ b/src/main/java/com/android/volley/toolbox/JsonRequest.java @@ -16,18 +16,18 @@ package com.android.volley.toolbox; +import android.support.annotation.GuardedBy; import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.Response.ErrorListener; import com.android.volley.Response.Listener; import com.android.volley.VolleyLog; - import java.io.UnsupportedEncodingException; /** - * A request for retrieving a T type response body at a given URL that also - * optionally sends along a JSON body in the request specified. + * A request for retrieving a T type response body at a given URL that also optionally sends along a + * JSON body in the request specified. * * @param <T> JSON type of response expected */ @@ -37,13 +37,14 @@ public abstract class JsonRequest<T> extends Request<T> { /** Content type for request. */ private static final String PROTOCOL_CONTENT_TYPE = - String.format("application/json; charset=%s", PROTOCOL_CHARSET); + String.format("application/json; charset=%s", PROTOCOL_CHARSET); /** Lock to guard mListener as it is cleared on cancel() and read on delivery. */ private final Object mLock = new Object(); - // @GuardedBy("mLock") + @GuardedBy("mLock") private Listener<T> mListener; + private final String mRequestBody; /** @@ -53,12 +54,16 @@ public abstract class JsonRequest<T> extends Request<T> { * @deprecated Use {@link #JsonRequest(int, String, String, Listener, ErrorListener)}. */ @Deprecated - public JsonRequest(String url, String requestBody, Listener<T> listener, - ErrorListener errorListener) { + public JsonRequest( + String url, String requestBody, Listener<T> listener, ErrorListener errorListener) { this(Method.DEPRECATED_GET_OR_POST, url, requestBody, listener, errorListener); } - public JsonRequest(int method, String url, String requestBody, Listener<T> listener, + public JsonRequest( + int method, + String url, + String requestBody, + Listener<T> listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; @@ -85,20 +90,16 @@ public abstract class JsonRequest<T> extends Request<T> { } @Override - abstract protected Response<T> parseNetworkResponse(NetworkResponse response); + protected abstract Response<T> parseNetworkResponse(NetworkResponse response); - /** - * @deprecated Use {@link #getBodyContentType()}. - */ + /** @deprecated Use {@link #getBodyContentType()}. */ @Deprecated @Override public String getPostBodyContentType() { return getBodyContentType(); } - /** - * @deprecated Use {@link #getBody()}. - */ + /** @deprecated Use {@link #getBody()}. */ @Deprecated @Override public byte[] getPostBody() { @@ -115,7 +116,8 @@ public abstract class JsonRequest<T> extends Request<T> { try { return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET); } catch (UnsupportedEncodingException uee) { - VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", + VolleyLog.wtf( + "Unsupported Encoding while trying to get the bytes of %s using %s", mRequestBody, PROTOCOL_CHARSET); return null; } diff --git a/src/main/java/com/android/volley/toolbox/NetworkImageView.java b/src/main/java/com/android/volley/toolbox/NetworkImageView.java index 60e4815..a490a79 100644 --- a/src/main/java/com/android/volley/toolbox/NetworkImageView.java +++ b/src/main/java/com/android/volley/toolbox/NetworkImageView.java @@ -1,46 +1,37 @@ /** * Copyright (C) 2013 The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * <p>http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and + * <p>Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ package com.android.volley.toolbox; import android.content.Context; +import android.support.annotation.MainThread; import android.text.TextUtils; import android.util.AttributeSet; import android.view.ViewGroup.LayoutParams; import android.widget.ImageView; - import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageLoader.ImageContainer; import com.android.volley.toolbox.ImageLoader.ImageListener; -/** - * Handles fetching an image from a URL as well as the life-cycle of the - * associated request. - */ +/** Handles fetching an image from a URL as well as the life-cycle of the associated request. */ public class NetworkImageView extends ImageView { /** The URL of the network image to load */ private String mUrl; - /** - * Resource ID of the image to be used as a placeholder until the network image is loaded. - */ + /** Resource ID of the image to be used as a placeholder until the network image is loaded. */ private int mDefaultImageId; - /** - * Resource ID of the image to be used if the network response fails. - */ + /** Resource ID of the image to be used if the network response fails. */ private int mErrorImageId; /** Local copy of the ImageLoader. */ @@ -66,18 +57,21 @@ public class NetworkImageView extends ImageView { * immediately either set the cached image (if available) or the default image specified by * {@link NetworkImageView#setDefaultImageResId(int)} on the view. * - * NOTE: If applicable, {@link NetworkImageView#setDefaultImageResId(int)} and - * {@link NetworkImageView#setErrorImageResId(int)} should be called prior to calling - * this function. + * <p>NOTE: If applicable, {@link NetworkImageView#setDefaultImageResId(int)} and {@link + * NetworkImageView#setErrorImageResId(int)} should be called prior to calling this function. + * + * <p>Must be called from the main thread. * * @param url The URL that should be loaded into this ImageView. * @param imageLoader ImageLoader that will be used to make the request. */ + @MainThread public void setImageUrl(String url, ImageLoader imageLoader) { + Threads.throwIfNotOnMainThread(); mUrl = url; mImageLoader = imageLoader; // The URL has potentially changed. See if we need to load it. - loadImageIfNecessary(false); + loadImageIfNecessary(/* isInLayoutPass= */ false); } /** @@ -98,6 +92,7 @@ public class NetworkImageView extends ImageView { /** * Loads the image for the view if it isn't already loaded. + * * @param isInLayoutPass True if this was invoked from a layout pass, false otherwise. */ void loadImageIfNecessary(final boolean isInLayoutPass) { @@ -149,45 +144,54 @@ public class NetworkImageView extends ImageView { // from the network. // update the ImageContainer to be the new bitmap container. - mImageContainer = mImageLoader.get(mUrl, - new ImageListener() { - @Override - public void onErrorResponse(VolleyError error) { - if (mErrorImageId != 0) { - setImageResource(mErrorImageId); - } - } - - @Override - public void onResponse(final ImageContainer response, boolean isImmediate) { - // If this was an immediate response that was delivered inside of a layout - // pass do not set the image immediately as it will trigger a requestLayout - // inside of a layout. Instead, defer setting the image by posting back to - // the main thread. - if (isImmediate && isInLayoutPass) { - post(new Runnable() { - @Override - public void run() { - onResponse(response, false); + mImageContainer = + mImageLoader.get( + mUrl, + new ImageListener() { + @Override + public void onErrorResponse(VolleyError error) { + if (mErrorImageId != 0) { + setImageResource(mErrorImageId); + } + } + + @Override + public void onResponse( + final ImageContainer response, boolean isImmediate) { + // If this was an immediate response that was delivered inside of a + // layout + // pass do not set the image immediately as it will trigger a + // requestLayout + // inside of a layout. Instead, defer setting the image by posting + // back to + // the main thread. + if (isImmediate && isInLayoutPass) { + post( + new Runnable() { + @Override + public void run() { + onResponse(response, /* isImmediate= */ false); + } + }); + return; } - }); - return; - } - - if (response.getBitmap() != null) { - setImageBitmap(response.getBitmap()); - } else if (mDefaultImageId != 0) { - setImageResource(mDefaultImageId); - } - } - }, maxWidth, maxHeight, scaleType); + + if (response.getBitmap() != null) { + setImageBitmap(response.getBitmap()); + } else if (mDefaultImageId != 0) { + setImageResource(mDefaultImageId); + } + } + }, + maxWidth, + maxHeight, + scaleType); } private void setDefaultImageOrNull() { - if(mDefaultImageId != 0) { + if (mDefaultImageId != 0) { setImageResource(mDefaultImageId); - } - else { + } else { setImageBitmap(null); } } @@ -195,7 +199,7 @@ public class NetworkImageView extends ImageView { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - loadImageIfNecessary(true); + loadImageIfNecessary(/* isInLayoutPass= */ true); } @Override diff --git a/src/main/java/com/android/volley/toolbox/NoCache.java b/src/main/java/com/android/volley/toolbox/NoCache.java index ab66254..51f9945 100644 --- a/src/main/java/com/android/volley/toolbox/NoCache.java +++ b/src/main/java/com/android/volley/toolbox/NoCache.java @@ -18,13 +18,10 @@ package com.android.volley.toolbox; import com.android.volley.Cache; -/** - * A cache that doesn't. - */ +/** A cache that doesn't. */ public class NoCache implements Cache { @Override - public void clear() { - } + public void clear() {} @Override public Entry get(String key) { @@ -32,18 +29,14 @@ public class NoCache implements Cache { } @Override - public void put(String key, Entry entry) { - } + public void put(String key, Entry entry) {} @Override - public void invalidate(String key, boolean fullExpire) { - } + public void invalidate(String key, boolean fullExpire) {} @Override - public void remove(String key) { - } + public void remove(String key) {} @Override - public void initialize() { - } + public void initialize() {} } diff --git a/src/main/java/com/android/volley/toolbox/PoolingByteArrayOutputStream.java b/src/main/java/com/android/volley/toolbox/PoolingByteArrayOutputStream.java index 9971566..bdcc45e 100644 --- a/src/main/java/com/android/volley/toolbox/PoolingByteArrayOutputStream.java +++ b/src/main/java/com/android/volley/toolbox/PoolingByteArrayOutputStream.java @@ -46,7 +46,7 @@ public class PoolingByteArrayOutputStream extends ByteArrayOutputStream { * expand. * * @param size initial size for the underlying byte array. The value will be pinned to a default - * minimum size. + * minimum size. */ public PoolingByteArrayOutputStream(ByteArrayPool pool, int size) { mPool = pool; @@ -65,9 +65,8 @@ public class PoolingByteArrayOutputStream extends ByteArrayOutputStream { mPool.returnBuf(buf); } - /** - * Ensures there is enough space in the buffer for the given number of additional bytes. - */ + /** Ensures there is enough space in the buffer for the given number of additional bytes. */ + @SuppressWarnings("UnsafeFinalization") private void expand(int i) { /* Can the buffer handle @i more bytes, if not expand it */ if (count + i <= buf.length) { diff --git a/src/main/java/com/android/volley/toolbox/RequestFuture.java b/src/main/java/com/android/volley/toolbox/RequestFuture.java index 173c44c..f9cbce2 100644 --- a/src/main/java/com/android/volley/toolbox/RequestFuture.java +++ b/src/main/java/com/android/volley/toolbox/RequestFuture.java @@ -16,10 +16,10 @@ package com.android.volley.toolbox; +import android.os.SystemClock; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; - import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -28,7 +28,8 @@ import java.util.concurrent.TimeoutException; /** * A Future that represents a Volley request. * - * Used by providing as your response and error listeners. For example: + * <p>Used by providing as your response and error listeners. For example: + * * <pre> * RequestFuture<JSONObject> future = RequestFuture.newFuture(); * MyRequest request = new MyRequest(URL, future, future); @@ -51,15 +52,14 @@ import java.util.concurrent.TimeoutException; * * @param <T> The type of parsed response this future expects. */ -public class RequestFuture<T> implements Future<T>, Response.Listener<T>, - Response.ErrorListener { +public class RequestFuture<T> implements Future<T>, Response.Listener<T>, Response.ErrorListener { private Request<?> mRequest; private boolean mResultReceived = false; private T mResult; private VolleyError mException; public static <E> RequestFuture<E> newFuture() { - return new RequestFuture<E>(); + return new RequestFuture<>(); } private RequestFuture() {} @@ -85,7 +85,7 @@ public class RequestFuture<T> implements Future<T>, Response.Listener<T>, @Override public T get() throws InterruptedException, ExecutionException { try { - return doGet(null); + return doGet(/* timeoutMs= */ null); } catch (TimeoutException e) { throw new AssertionError(e); } @@ -108,9 +108,16 @@ public class RequestFuture<T> implements Future<T>, Response.Listener<T>, } if (timeoutMs == null) { - wait(0); + while (!isDone()) { + wait(0); + } } else if (timeoutMs > 0) { - wait(timeoutMs); + long nowMs = SystemClock.uptimeMillis(); + long deadlineMs = nowMs + timeoutMs; + while (!isDone() && nowMs < deadlineMs) { + wait(deadlineMs - nowMs); + nowMs = SystemClock.uptimeMillis(); + } } if (mException != null) { @@ -150,4 +157,3 @@ public class RequestFuture<T> implements Future<T>, Response.Listener<T>, notifyAll(); } } - diff --git a/src/main/java/com/android/volley/toolbox/StringRequest.java b/src/main/java/com/android/volley/toolbox/StringRequest.java index 9deba1d..0fbab14 100644 --- a/src/main/java/com/android/volley/toolbox/StringRequest.java +++ b/src/main/java/com/android/volley/toolbox/StringRequest.java @@ -16,23 +16,21 @@ package com.android.volley.toolbox; +import android.support.annotation.GuardedBy; import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.Response.ErrorListener; import com.android.volley.Response.Listener; - import java.io.UnsupportedEncodingException; -/** - * A canned request for retrieving the response body at a given URL as a String. - */ +/** A canned request for retrieving the response body at a given URL as a String. */ public class StringRequest extends Request<String> { /** Lock to guard mListener as it is cleared on cancel() and read on delivery. */ private final Object mLock = new Object(); - // @GuardedBy("mLock") + @GuardedBy("mLock") private Listener<String> mListener; /** @@ -43,8 +41,8 @@ public class StringRequest extends Request<String> { * @param listener Listener to receive the String response * @param errorListener Error listener, or null to ignore errors */ - public StringRequest(int method, String url, Listener<String> listener, - ErrorListener errorListener) { + public StringRequest( + int method, String url, Listener<String> listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } @@ -80,11 +78,15 @@ public class StringRequest extends Request<String> { } @Override + @SuppressWarnings("DefaultCharset") protected Response<String> parseNetworkResponse(NetworkResponse response) { String parsed; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException e) { + // Since minSdkVersion = 8, we can't call + // new String(response.data, Charset.defaultCharset()) + // So suppress the warning instead. parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); diff --git a/src/main/java/com/android/volley/toolbox/Threads.java b/src/main/java/com/android/volley/toolbox/Threads.java new file mode 100644 index 0000000..66c3e41 --- /dev/null +++ b/src/main/java/com/android/volley/toolbox/Threads.java @@ -0,0 +1,13 @@ +package com.android.volley.toolbox; + +import android.os.Looper; + +final class Threads { + private Threads() {} + + static void throwIfNotOnMainThread() { + if (Looper.myLooper() != Looper.getMainLooper()) { + throw new IllegalStateException("Must be invoked from the main thread."); + } + } +} diff --git a/src/main/java/com/android/volley/toolbox/Volley.java b/src/main/java/com/android/volley/toolbox/Volley.java index 6ec08b1..1982802 100644 --- a/src/main/java/com/android/volley/toolbox/Volley.java +++ b/src/main/java/com/android/volley/toolbox/Volley.java @@ -21,10 +21,8 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.net.http.AndroidHttpClient; import android.os.Build; - import com.android.volley.Network; import com.android.volley.RequestQueue; - import java.io.File; public class Volley { @@ -52,13 +50,15 @@ public class Volley { String userAgent = "volley/0"; try { String packageName = context.getPackageName(); - PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); + PackageInfo info = + context.getPackageManager().getPackageInfo(packageName, /* flags= */ 0); userAgent = packageName + "/" + info.versionCode; } catch (NameNotFoundException e) { } - network = new BasicNetwork( - new HttpClientStack(AndroidHttpClient.newInstance(userAgent))); + network = + new BasicNetwork( + new HttpClientStack(AndroidHttpClient.newInstance(userAgent))); } } else { network = new BasicNetwork(stack); @@ -74,7 +74,7 @@ public class Volley { * @param stack An {@link HttpStack} to use for the network, or null for default. * @return A started {@link RequestQueue} instance. * @deprecated Use {@link #newRequestQueue(Context, BaseHttpStack)} instead to avoid depending - * on Apache HTTP. This method may be removed in a future release of Volley. + * on Apache HTTP. This method may be removed in a future release of Volley. */ @Deprecated @SuppressWarnings("deprecation") diff --git a/src/test/java/com/android/volley/CacheDispatcherTest.java b/src/test/java/com/android/volley/CacheDispatcherTest.java index a39be7b..9c5d3c3 100644 --- a/src/test/java/com/android/volley/CacheDispatcherTest.java +++ b/src/test/java/com/android/volley/CacheDispatcherTest.java @@ -16,183 +16,219 @@ package com.android.volley; -import com.android.volley.mock.MockCache; -import com.android.volley.mock.MockRequest; -import com.android.volley.mock.MockResponseDelivery; -import com.android.volley.mock.WaitableQueue; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.android.volley.toolbox.StringRequest; import com.android.volley.utils.CacheTestUtils; - -import org.junit.After; +import java.util.concurrent.BlockingQueue; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; -import static org.junit.Assert.*; - @RunWith(RobolectricTestRunner.class) @SuppressWarnings("rawtypes") public class CacheDispatcherTest { private CacheDispatcher mDispatcher; - private WaitableQueue mCacheQueue; - private WaitableQueue mNetworkQueue; - private MockCache mCache; - private MockResponseDelivery mDelivery; - private MockRequest mRequest; + private @Mock BlockingQueue<Request<?>> mCacheQueue; + private @Mock BlockingQueue<Request<?>> mNetworkQueue; + private @Mock Cache mCache; + private @Mock ResponseDelivery mDelivery; + private StringRequest mRequest; - private static final long TIMEOUT_MILLIS = 5000; + @Before + public void setUp() throws Exception { + initMocks(this); - @Before public void setUp() throws Exception { - mCacheQueue = new WaitableQueue(); - mNetworkQueue = new WaitableQueue(); - mCache = new MockCache(); - mDelivery = new MockResponseDelivery(); + mRequest = new StringRequest(Request.Method.GET, "http://foo", null, null); + mDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); + } - mRequest = new MockRequest(); + private static class WaitForever implements Answer { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + Thread.sleep(Long.MAX_VALUE); + return null; + } + } - mDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); + @Test + public void runStopsOnQuit() throws Exception { + when(mCacheQueue.take()).then(new WaitForever()); mDispatcher.start(); + mDispatcher.quit(); + mDispatcher.join(1000); } - @After public void tearDown() throws Exception { - mDispatcher.quit(); - mDispatcher.join(); + private static void verifyNoResponse(ResponseDelivery delivery) { + verify(delivery, never()).postResponse(any(Request.class), any(Response.class)); + verify(delivery, never()) + .postResponse(any(Request.class), any(Response.class), any(Runnable.class)); + verify(delivery, never()).postError(any(Request.class), any(VolleyError.class)); } // A cancelled request should not be processed at all. - @Test public void cancelledRequest() throws Exception { + @Test + public void cancelledRequest() throws Exception { mRequest.cancel(); - mCacheQueue.add(mRequest); - mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); - assertFalse(mCache.getCalled); - assertFalse(mDelivery.wasEitherResponseCalled()); + mDispatcher.processRequest(mRequest); + verify(mCache, never()).get(anyString()); + verifyNoResponse(mDelivery); } // A cache miss does not post a response and puts the request on the network queue. - @Test public void cacheMiss() throws Exception { - mCacheQueue.add(mRequest); - mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); - assertFalse(mDelivery.wasEitherResponseCalled()); - assertTrue(mNetworkQueue.size() > 0); - Request request = mNetworkQueue.take(); - assertNull(request.getCacheEntry()); + @Test + public void cacheMiss() throws Exception { + mDispatcher.processRequest(mRequest); + verifyNoResponse(mDelivery); + verify(mNetworkQueue).put(mRequest); + assertNull(mRequest.getCacheEntry()); } // A non-expired cache hit posts a response and does not queue to the network. - @Test public void nonExpiredCacheHit() throws Exception { + @Test + public void nonExpiredCacheHit() throws Exception { Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, false, false); - mCache.setEntryToReturn(entry); - mCacheQueue.add(mRequest); - mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); - assertTrue(mDelivery.postResponse_called); - assertFalse(mDelivery.postError_called); + when(mCache.get(anyString())).thenReturn(entry); + mDispatcher.processRequest(mRequest); + verify(mDelivery).postResponse(any(Request.class), any(Response.class)); + verify(mDelivery, never()).postError(any(Request.class), any(VolleyError.class)); } // A soft-expired cache hit posts a response and queues to the network. - @Test public void softExpiredCacheHit() throws Exception { + @Test + public void softExpiredCacheHit() throws Exception { Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, false, true); - mCache.setEntryToReturn(entry); - mCacheQueue.add(mRequest); - mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); - assertTrue(mDelivery.postResponse_called); - assertFalse(mDelivery.postError_called); - assertTrue(mNetworkQueue.size() > 0); - Request request = mNetworkQueue.take(); - assertSame(entry, request.getCacheEntry()); + when(mCache.get(anyString())).thenReturn(entry); + mDispatcher.processRequest(mRequest); + + // Soft expiration needs to use the deferred Runnable variant of postResponse, + // so make sure it gets to run. + ArgumentCaptor<Runnable> runnable = ArgumentCaptor.forClass(Runnable.class); + verify(mDelivery).postResponse(any(Request.class), any(Response.class), runnable.capture()); + runnable.getValue().run(); + // This way we can verify the behavior of the Runnable as well. + verify(mNetworkQueue).put(mRequest); + assertSame(entry, mRequest.getCacheEntry()); + + verify(mDelivery, never()).postError(any(Request.class), any(VolleyError.class)); } // An expired cache hit does not post a response and queues to the network. - @Test public void expiredCacheHit() throws Exception { + @Test + public void expiredCacheHit() throws Exception { Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, true, true); - mCache.setEntryToReturn(entry); - mCacheQueue.add(mRequest); - mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); - assertFalse(mDelivery.wasEitherResponseCalled()); - assertTrue(mNetworkQueue.size() > 0); - Request request = mNetworkQueue.take(); - assertSame(entry, request.getCacheEntry()); + when(mCache.get(anyString())).thenReturn(entry); + mDispatcher.processRequest(mRequest); + verifyNoResponse(mDelivery); + verify(mNetworkQueue).put(mRequest); + assertSame(entry, mRequest.getCacheEntry()); } - @Test public void duplicateCacheMiss() throws Exception { - MockRequest secondRequest = new MockRequest(); + @Test + public void duplicateCacheMiss() throws Exception { + StringRequest secondRequest = + new StringRequest(Request.Method.GET, "http://foo", null, null); mRequest.setSequence(1); secondRequest.setSequence(2); - mCacheQueue.add(mRequest); - mCacheQueue.add(secondRequest); - mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); - assertTrue(mNetworkQueue.size() == 1); - assertFalse(mDelivery.postResponse_called); + mDispatcher.processRequest(mRequest); + mDispatcher.processRequest(secondRequest); + verify(mNetworkQueue).put(mRequest); + verifyNoResponse(mDelivery); } - @Test public void tripleCacheMiss_networkErrorOnFirst() throws Exception { - MockRequest secondRequest = new MockRequest(); - MockRequest thirdRequest = new MockRequest(); + @Test + public void tripleCacheMiss_networkErrorOnFirst() throws Exception { + StringRequest secondRequest = + new StringRequest(Request.Method.GET, "http://foo", null, null); + StringRequest thirdRequest = + new StringRequest(Request.Method.GET, "http://foo", null, null); mRequest.setSequence(1); secondRequest.setSequence(2); thirdRequest.setSequence(3); - mCacheQueue.add(mRequest); - mCacheQueue.add(secondRequest); - mCacheQueue.add(thirdRequest); - mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); + mDispatcher.processRequest(mRequest); + mDispatcher.processRequest(secondRequest); + mDispatcher.processRequest(thirdRequest); - assertTrue(mNetworkQueue.size() == 1); - assertFalse(mDelivery.postResponse_called); + verify(mNetworkQueue).put(mRequest); + verifyNoResponse(mDelivery); - Request request = mNetworkQueue.take(); - request.notifyListenerResponseNotUsable(); + ((Request<?>) mRequest).notifyListenerResponseNotUsable(); // Second request should now be in network queue. - assertTrue(mNetworkQueue.size() == 1); - request = mNetworkQueue.take(); - assertTrue(request.equals(secondRequest)); + verify(mNetworkQueue).put(secondRequest); // Another unusable response, third request should now be added. - request.notifyListenerResponseNotUsable(); - assertTrue(mNetworkQueue.size() == 1); - request = mNetworkQueue.take(); - assertTrue(request.equals(thirdRequest)); + ((Request<?>) secondRequest).notifyListenerResponseNotUsable(); + verify(mNetworkQueue).put(thirdRequest); } - @Test public void duplicateSoftExpiredCacheHit_failedRequest() throws Exception { + @Test + public void duplicateSoftExpiredCacheHit_failedRequest() throws Exception { Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, false, true); - mCache.setEntryToReturn(entry); + when(mCache.get(anyString())).thenReturn(entry); - MockRequest secondRequest = new MockRequest(); + StringRequest secondRequest = + new StringRequest(Request.Method.GET, "http://foo", null, null); mRequest.setSequence(1); secondRequest.setSequence(2); - mCacheQueue.add(mRequest); - mCacheQueue.add(secondRequest); - mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); + mDispatcher.processRequest(mRequest); + mDispatcher.processRequest(secondRequest); - assertTrue(mNetworkQueue.size() == 1); - assertTrue(mDelivery.postResponse_calledNtimes == 2); + // Soft expiration needs to use the deferred Runnable variant of postResponse, + // so make sure it gets to run. + ArgumentCaptor<Runnable> runnable = ArgumentCaptor.forClass(Runnable.class); + verify(mDelivery).postResponse(any(Request.class), any(Response.class), runnable.capture()); + runnable.getValue().run(); + // This way we can verify the behavior of the Runnable as well. - Request request = mNetworkQueue.take(); - request.notifyListenerResponseNotUsable(); + verify(mNetworkQueue).put(mRequest); + verify(mDelivery) + .postResponse(any(Request.class), any(Response.class), any(Runnable.class)); + + ((Request<?>) mRequest).notifyListenerResponseNotUsable(); // Second request should now be in network queue. - assertTrue(mNetworkQueue.size() == 1); - request = mNetworkQueue.take(); - assertTrue(request.equals(secondRequest)); + verify(mNetworkQueue).put(secondRequest); } - @Test public void duplicateSoftExpiredCacheHit_successfulRequest() throws Exception { + @Test + public void duplicateSoftExpiredCacheHit_successfulRequest() throws Exception { Cache.Entry entry = CacheTestUtils.makeRandomCacheEntry(null, false, true); - mCache.setEntryToReturn(entry); + when(mCache.get(anyString())).thenReturn(entry); - MockRequest secondRequest = new MockRequest(); + StringRequest secondRequest = + new StringRequest(Request.Method.GET, "http://foo", null, null); mRequest.setSequence(1); secondRequest.setSequence(2); - mCacheQueue.add(mRequest); - mCacheQueue.add(secondRequest); - mCacheQueue.waitUntilEmpty(TIMEOUT_MILLIS); + mDispatcher.processRequest(mRequest); + mDispatcher.processRequest(secondRequest); + + // Soft expiration needs to use the deferred Runnable variant of postResponse, + // so make sure it gets to run. + ArgumentCaptor<Runnable> runnable = ArgumentCaptor.forClass(Runnable.class); + verify(mDelivery).postResponse(any(Request.class), any(Response.class), runnable.capture()); + runnable.getValue().run(); + // This way we can verify the behavior of the Runnable as well. - assertTrue(mNetworkQueue.size() == 1); - assertTrue(mDelivery.postResponse_calledNtimes == 2); + verify(mNetworkQueue).put(mRequest); + verify(mDelivery) + .postResponse(any(Request.class), any(Response.class), any(Runnable.class)); - Request request = mNetworkQueue.take(); - request.notifyListenerResponseReceived(Response.success(null, entry)); + ((Request<?>) mRequest).notifyListenerResponseReceived(Response.success(null, entry)); // Second request should have delivered response. - assertTrue(mNetworkQueue.size() == 0); - assertTrue(mDelivery.postResponse_calledNtimes == 3); + verify(mNetworkQueue, never()).put(secondRequest); + verify(mDelivery) + .postResponse(any(Request.class), any(Response.class), any(Runnable.class)); } } diff --git a/src/test/java/com/android/volley/NetworkDispatcherTest.java b/src/test/java/com/android/volley/NetworkDispatcherTest.java index c5763bd..51c6971 100644 --- a/src/test/java/com/android/volley/NetworkDispatcherTest.java +++ b/src/test/java/com/android/volley/NetworkDispatcherTest.java @@ -16,85 +16,84 @@ package com.android.volley; -import com.android.volley.mock.MockCache; -import com.android.volley.mock.MockNetwork; -import com.android.volley.mock.MockRequest; -import com.android.volley.mock.MockResponseDelivery; -import com.android.volley.mock.WaitableQueue; -import org.junit.After; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.android.volley.toolbox.StringRequest; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.concurrent.BlockingQueue; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; import org.robolectric.RobolectricTestRunner; -import java.util.Arrays; - -import static org.junit.Assert.*; - @RunWith(RobolectricTestRunner.class) public class NetworkDispatcherTest { private NetworkDispatcher mDispatcher; - private MockResponseDelivery mDelivery; - private WaitableQueue mNetworkQueue; - private MockNetwork mNetwork; - private MockCache mCache; - private MockRequest mRequest; + private @Mock ResponseDelivery mDelivery; + private @Mock BlockingQueue<Request<?>> mNetworkQueue; + private @Mock Network mNetwork; + private @Mock Cache mCache; + private StringRequest mRequest; - private static final byte[] CANNED_DATA = "Ceci n'est pas une vraie reponse".getBytes(); - private static final long TIMEOUT_MILLIS = 5000; + private static final byte[] CANNED_DATA = + "Ceci n'est pas une vraie reponse".getBytes(StandardCharsets.UTF_8); - @Before public void setUp() throws Exception { - mDelivery = new MockResponseDelivery(); - mNetworkQueue = new WaitableQueue(); - mNetwork = new MockNetwork(); - mCache = new MockCache(); - mRequest = new MockRequest(); + @Before + public void setUp() throws Exception { + initMocks(this); + mRequest = new StringRequest(Request.Method.GET, "http://foo", null, null); mDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); - mDispatcher.start(); } - @After public void tearDown() throws Exception { - mDispatcher.quit(); - mDispatcher.join(); - } + @Test + public void successPostsResponse() throws Exception { + when(mNetwork.performRequest(any(Request.class))) + .thenReturn(new NetworkResponse(CANNED_DATA)); + mDispatcher.processRequest(mRequest); - @Test public void successPostsResponse() throws Exception { - mNetwork.setDataToReturn(CANNED_DATA); - mNetwork.setNumExceptionsToThrow(0); - mNetworkQueue.add(mRequest); - mNetworkQueue.waitUntilEmpty(TIMEOUT_MILLIS); - assertFalse(mDelivery.postError_called); - assertTrue(mDelivery.postResponse_called); - Response<?> response = mDelivery.responsePosted; - assertNotNull(response); - assertTrue(response.isSuccess()); - assertTrue(Arrays.equals((byte[])response.result, CANNED_DATA)); + ArgumentCaptor<Response> response = ArgumentCaptor.forClass(Response.class); + verify(mDelivery).postResponse(any(Request.class), response.capture()); + assertTrue(response.getValue().isSuccess()); + assertEquals(response.getValue().result, new String(CANNED_DATA, StandardCharsets.UTF_8)); + + verify(mDelivery, never()).postError(any(Request.class), any(VolleyError.class)); } - @Test public void exceptionPostsError() throws Exception { - mNetwork.setNumExceptionsToThrow(MockNetwork.ALWAYS_THROW_EXCEPTIONS); - mNetworkQueue.add(mRequest); - mNetworkQueue.waitUntilEmpty(TIMEOUT_MILLIS); - assertFalse(mDelivery.postResponse_called); - assertTrue(mDelivery.postError_called); + @Test + public void exceptionPostsError() throws Exception { + when(mNetwork.performRequest(any(Request.class))).thenThrow(new ServerError()); + mDispatcher.processRequest(mRequest); + + verify(mDelivery).postError(any(Request.class), any(VolleyError.class)); + verify(mDelivery, never()).postResponse(any(Request.class), any(Response.class)); } - @Test public void shouldCacheFalse() throws Exception { + @Test + public void shouldCacheFalse() throws Exception { mRequest.setShouldCache(false); - mNetworkQueue.add(mRequest); - mNetworkQueue.waitUntilEmpty(TIMEOUT_MILLIS); - assertFalse(mCache.putCalled); + mDispatcher.processRequest(mRequest); + verify(mCache, never()).put(anyString(), any(Cache.Entry.class)); } - @Test public void shouldCacheTrue() throws Exception { - mNetwork.setDataToReturn(CANNED_DATA); + @Test + public void shouldCacheTrue() throws Exception { + when(mNetwork.performRequest(any(Request.class))) + .thenReturn(new NetworkResponse(CANNED_DATA)); mRequest.setShouldCache(true); - mRequest.setCacheKey("bananaphone"); - mNetworkQueue.add(mRequest); - mNetworkQueue.waitUntilEmpty(TIMEOUT_MILLIS); - assertTrue(mCache.putCalled); - assertNotNull(mCache.entryPut); - assertTrue(Arrays.equals(mCache.entryPut.data, CANNED_DATA)); - assertEquals("bananaphone", mCache.keyPut); + mDispatcher.processRequest(mRequest); + ArgumentCaptor<Cache.Entry> entry = ArgumentCaptor.forClass(Cache.Entry.class); + verify(mCache).put(eq(mRequest.getCacheKey()), entry.capture()); + assertTrue(Arrays.equals(entry.getValue().data, CANNED_DATA)); } } diff --git a/src/test/java/com/android/volley/NetworkResponseTest.java b/src/test/java/com/android/volley/NetworkResponseTest.java index be34143..48b1f6d 100644 --- a/src/test/java/com/android/volley/NetworkResponseTest.java +++ b/src/test/java/com/android/volley/NetworkResponseTest.java @@ -1,18 +1,17 @@ package com.android.volley; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; - -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class NetworkResponseTest { @@ -30,7 +29,8 @@ public class NetworkResponseTest { expectedHeaders.add(new Header("key1", "value1")); expectedHeaders.add(new Header("key2", "value2")); - assertThat(expectedHeaders, + assertThat( + expectedHeaders, containsInAnyOrder(resp.allHeaders.toArray(new Header[resp.allHeaders.size()]))); } diff --git a/src/test/java/com/android/volley/RequestQueueIntegrationTest.java b/src/test/java/com/android/volley/RequestQueueIntegrationTest.java index 304a1ab..a2bfbc6 100644 --- a/src/test/java/com/android/volley/RequestQueueIntegrationTest.java +++ b/src/test/java/com/android/volley/RequestQueueIntegrationTest.java @@ -16,13 +16,19 @@ package com.android.volley; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + import com.android.volley.Request.Priority; import com.android.volley.RequestQueue.RequestFinishedListener; import com.android.volley.mock.MockRequest; import com.android.volley.mock.ShadowSystemClock; import com.android.volley.toolbox.NoCache; import com.android.volley.utils.ImmediateResponseDelivery; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,14 +39,6 @@ import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - - /** * Integration tests for {@link RequestQueue} that verify its behavior in conjunction with real * dispatcher, queues and Requests. @@ -56,12 +54,14 @@ public class RequestQueueIntegrationTest { @Mock private RequestFinishedListener<byte[]> mMockListener; @Mock private RequestFinishedListener<byte[]> mMockListener2; - @Before public void setUp() throws Exception { + @Before + public void setUp() throws Exception { mDelivery = new ImmediateResponseDelivery(); initMocks(this); } - @Test public void add_requestProcessedInCorrectOrder() throws Exception { + @Test + public void add_requestProcessedInCorrectOrder() throws Exception { // Enqueue 2 requests with different cache keys, and different priorities. The second, // higher priority request takes 20ms. // Assert that the first request is only handled after the first one has been parsed and @@ -73,13 +73,15 @@ public class RequestQueueIntegrationTest { lowerPriorityReq.setPriority(Priority.LOW); higherPriorityReq.setPriority(Priority.HIGH); - Answer<NetworkResponse> delayAnswer = new Answer<NetworkResponse>() { - @Override - public NetworkResponse answer(InvocationOnMock invocationOnMock) throws Throwable { - Thread.sleep(20); - return mock(NetworkResponse.class); - } - }; + Answer<NetworkResponse> delayAnswer = + new Answer<NetworkResponse>() { + @Override + public NetworkResponse answer(InvocationOnMock invocationOnMock) + throws Throwable { + Thread.sleep(20); + return mock(NetworkResponse.class); + } + }; // delay only for higher request when(mMockNetwork.performRequest(higherPriorityReq)).thenAnswer(delayAnswer); when(mMockNetwork.performRequest(lowerPriorityReq)).thenReturn(mock(NetworkResponse.class)); @@ -100,19 +102,22 @@ public class RequestQueueIntegrationTest { } /** Asserts that requests with same cache key are processed in order. */ - @Test public void add_dedupeByCacheKey() throws Exception { + @Test + public void add_dedupeByCacheKey() throws Exception { // Enqueue 2 requests with the same cache key. The first request takes 20ms. Assert that the // second request is only handled after the first one has been parsed and delivered. MockRequest req1 = new MockRequest(); MockRequest req2 = new MockRequest(); - Answer<NetworkResponse> delayAnswer = new Answer<NetworkResponse>() { - @Override - public NetworkResponse answer(InvocationOnMock invocationOnMock) throws Throwable { - Thread.sleep(20); - return mock(NetworkResponse.class); - } - }; - //delay only for first + Answer<NetworkResponse> delayAnswer = + new Answer<NetworkResponse>() { + @Override + public NetworkResponse answer(InvocationOnMock invocationOnMock) + throws Throwable { + Thread.sleep(20); + return mock(NetworkResponse.class); + } + }; + // delay only for first when(mMockNetwork.performRequest(req1)).thenAnswer(delayAnswer); when(mMockNetwork.performRequest(req2)).thenReturn(mock(NetworkResponse.class)); @@ -131,16 +136,19 @@ public class RequestQueueIntegrationTest { queue.stop(); } - /** Verify RequestFinishedListeners are informed when requests are canceled. */ - @Test public void add_requestFinishedListenerCanceled() throws Exception { + /** Verify RequestFinishedListeners are informed when requests are canceled. */ + @Test + public void add_requestFinishedListenerCanceled() throws Exception { MockRequest request = new MockRequest(); - Answer<NetworkResponse> delayAnswer = new Answer<NetworkResponse>() { - @Override - public NetworkResponse answer(InvocationOnMock invocationOnMock) throws Throwable { - Thread.sleep(200); - return mock(NetworkResponse.class); - } - }; + Answer<NetworkResponse> delayAnswer = + new Answer<NetworkResponse>() { + @Override + public NetworkResponse answer(InvocationOnMock invocationOnMock) + throws Throwable { + Thread.sleep(200); + return mock(NetworkResponse.class); + } + }; RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 1, mDelivery); when(mMockNetwork.performRequest(request)).thenAnswer(delayAnswer); @@ -155,7 +163,8 @@ public class RequestQueueIntegrationTest { } /** Verify RequestFinishedListeners are informed when requests are successfully delivered. */ - @Test public void add_requestFinishedListenerSuccess() throws Exception { + @Test + public void add_requestFinishedListenerSuccess() throws Exception { MockRequest request = new MockRequest(); RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 1, mDelivery); @@ -171,7 +180,8 @@ public class RequestQueueIntegrationTest { } /** Verify RequestFinishedListeners are informed when request errors. */ - @Test public void add_requestFinishedListenerError() throws Exception { + @Test + public void add_requestFinishedListenerError() throws Exception { MockRequest request = new MockRequest(); RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 1, mDelivery); diff --git a/src/test/java/com/android/volley/RequestQueueTest.java b/src/test/java/com/android/volley/RequestQueueTest.java index bcf3ff2..11c6fe2 100644 --- a/src/test/java/com/android/volley/RequestQueueTest.java +++ b/src/test/java/com/android/volley/RequestQueueTest.java @@ -16,8 +16,15 @@ package com.android.volley; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + import com.android.volley.mock.ShadowSystemClock; import com.android.volley.toolbox.NoCache; +import com.android.volley.toolbox.StringRequest; import com.android.volley.utils.ImmediateResponseDelivery; import org.junit.Before; import org.junit.Test; @@ -26,13 +33,7 @@ import org.mockito.Mock; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; -import static org.mockito.MockitoAnnotations.initMocks; - -/** - * Unit tests for RequestQueue, with all dependencies mocked out - */ +/** Unit tests for RequestQueue, with all dependencies mocked out */ @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowSystemClock.class}) public class RequestQueueTest { @@ -40,22 +41,24 @@ public class RequestQueueTest { private ResponseDelivery mDelivery; @Mock private Network mMockNetwork; - @Before public void setUp() throws Exception { + @Before + public void setUp() throws Exception { mDelivery = new ImmediateResponseDelivery(); initMocks(this); } - @Test public void cancelAll_onlyCorrectTag() throws Exception { + @Test + public void cancelAll_onlyCorrectTag() throws Exception { RequestQueue queue = new RequestQueue(new NoCache(), mMockNetwork, 0, mDelivery); Object tagA = new Object(); Object tagB = new Object(); - Request req1 = mock(Request.class); + StringRequest req1 = mock(StringRequest.class); when(req1.getTag()).thenReturn(tagA); - Request req2 = mock(Request.class); + StringRequest req2 = mock(StringRequest.class); when(req2.getTag()).thenReturn(tagB); - Request req3 = mock(Request.class); + StringRequest req3 = mock(StringRequest.class); when(req3.getTag()).thenReturn(tagA); - Request req4 = mock(Request.class); + StringRequest req4 = mock(StringRequest.class); when(req4.getTag()).thenReturn(tagA); queue.add(req1); // A diff --git a/src/test/java/com/android/volley/RequestTest.java b/src/test/java/com/android/volley/RequestTest.java index d5beca5..e2dd655 100644 --- a/src/test/java/com/android/volley/RequestTest.java +++ b/src/test/java/com/android/volley/RequestTest.java @@ -16,17 +16,20 @@ package com.android.volley; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import com.android.volley.Request.Priority; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import static org.junit.Assert.*; - @RunWith(RobolectricTestRunner.class) public class RequestTest { - - @Test public void compareTo() { + + @Test + public void compareTo() { int sequence = 0; TestRequest low = new TestRequest(Priority.LOW); low.setSequence(sequence++); @@ -45,8 +48,9 @@ public class RequestTest { assertTrue(immediate.compareTo(high) < 0); } - private class TestRequest extends Request<Object> { + private static class TestRequest extends Request<Object> { private Priority mPriority = Priority.NORMAL; + public TestRequest(Priority priority) { super(Request.Method.GET, "", null); mPriority = priority; @@ -58,8 +62,7 @@ public class RequestTest { } @Override - protected void deliverResponse(Object response) { - } + protected void deliverResponse(Object response) {} @Override protected Response<Object> parseNetworkResponse(NetworkResponse response) { @@ -67,7 +70,8 @@ public class RequestTest { } } - @Test public void urlParsing() { + @Test + public void urlParsing() { UrlParseRequest nullUrl = new UrlParseRequest(null); assertEquals(0, nullUrl.getTrafficStatsTag()); UrlParseRequest emptyUrl = new UrlParseRequest(""); @@ -80,14 +84,13 @@ public class RequestTest { assertFalse(0 == goodProtocol.getTrafficStatsTag()); } - private class UrlParseRequest extends Request<Object> { + private static class UrlParseRequest extends Request<Object> { public UrlParseRequest(String url) { super(Request.Method.GET, url, null); } @Override - protected void deliverResponse(Object response) { - } + protected void deliverResponse(Object response) {} @Override protected Response<Object> parseNetworkResponse(NetworkResponse response) { diff --git a/src/test/java/com/android/volley/ResponseDeliveryTest.java b/src/test/java/com/android/volley/ResponseDeliveryTest.java index 9fadfc3..6e71c3b 100644 --- a/src/test/java/com/android/volley/ResponseDeliveryTest.java +++ b/src/test/java/com/android/volley/ResponseDeliveryTest.java @@ -16,18 +16,17 @@ package com.android.volley; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import com.android.volley.mock.MockRequest; import com.android.volley.utils.CacheTestUtils; import com.android.volley.utils.ImmediateResponseDelivery; - -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import static org.junit.Assert.*; - @RunWith(RobolectricTestRunner.class) public class ResponseDeliveryTest { @@ -35,7 +34,8 @@ public class ResponseDeliveryTest { private MockRequest mRequest; private Response<byte[]> mSuccessResponse; - @Before public void setUp() throws Exception { + @Before + public void setUp() throws Exception { // Make the delivery just run its posted responses immediately. mDelivery = new ImmediateResponseDelivery(); mRequest = new MockRequest(); @@ -45,20 +45,23 @@ public class ResponseDeliveryTest { mSuccessResponse = Response.success(data, cacheEntry); } - @Test public void postResponseCallsDeliverResponse() { + @Test + public void postResponseCallsDeliverResponse() { mDelivery.postResponse(mRequest, mSuccessResponse); assertTrue(mRequest.deliverResponse_called); assertFalse(mRequest.deliverError_called); } - @Test public void postResponseSuppressesCanceled() { + @Test + public void postResponseSuppressesCanceled() { mRequest.cancel(); mDelivery.postResponse(mRequest, mSuccessResponse); assertFalse(mRequest.deliverResponse_called); assertFalse(mRequest.deliverError_called); } - @Test public void postErrorCallsDeliverError() { + @Test + public void postErrorCallsDeliverError() { Response<byte[]> errorResponse = Response.error(new ServerError()); mDelivery.postResponse(mRequest, errorResponse); diff --git a/src/test/java/com/android/volley/mock/MockCache.java b/src/test/java/com/android/volley/mock/MockCache.java deleted file mode 100644 index 85a4607..0000000 --- a/src/test/java/com/android/volley/mock/MockCache.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.volley.mock; - -import com.android.volley.Cache; - -public class MockCache implements Cache { - - public boolean clearCalled = false; - @Override - public void clear() { - clearCalled = true; - } - - public boolean getCalled = false; - private Entry mFakeEntry = null; - - public void setEntryToReturn(Entry entry) { - mFakeEntry = entry; - } - - @Override - public Entry get(String key) { - getCalled = true; - return mFakeEntry; - } - - public boolean putCalled = false; - public String keyPut = null; - public Entry entryPut = null; - - @Override - public void put(String key, Entry entry) { - putCalled = true; - keyPut = key; - entryPut = entry; - } - - @Override - public void invalidate(String key, boolean fullExpire) { - } - - @Override - public void remove(String key) { - } - - @Override - public void initialize() { - } - -} diff --git a/src/test/java/com/android/volley/mock/MockHttpStack.java b/src/test/java/com/android/volley/mock/MockHttpStack.java index 56b29f1..b86e7a0 100644 --- a/src/test/java/com/android/volley/mock/MockHttpStack.java +++ b/src/test/java/com/android/volley/mock/MockHttpStack.java @@ -20,7 +20,6 @@ import com.android.volley.AuthFailureError; import com.android.volley.Request; import com.android.volley.toolbox.BaseHttpStack; import com.android.volley.toolbox.HttpResponse; - import java.io.IOException; import java.util.HashMap; import java.util.Map; diff --git a/src/test/java/com/android/volley/mock/MockHttpURLConnection.java b/src/test/java/com/android/volley/mock/MockHttpURLConnection.java deleted file mode 100644 index efa3a21..0000000 --- a/src/test/java/com/android/volley/mock/MockHttpURLConnection.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.volley.mock; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; - -public class MockHttpURLConnection extends HttpURLConnection { - - private boolean mDoOutput; - private String mRequestMethod; - private OutputStream mOutputStream; - - public MockHttpURLConnection() throws MalformedURLException { - super(new URL("http://foo.com")); - mDoOutput = false; - mRequestMethod = "GET"; - mOutputStream = new ByteArrayOutputStream(); - } - - @Override - public void setDoOutput(boolean flag) { - mDoOutput = flag; - } - - @Override - public boolean getDoOutput() { - return mDoOutput; - } - - @Override - public void setRequestMethod(String method) { - mRequestMethod = method; - } - - @Override - public String getRequestMethod() { - return mRequestMethod; - } - - @Override - public OutputStream getOutputStream() { - return mOutputStream; - } - - @Override - public void disconnect() { - } - - @Override - public boolean usingProxy() { - return false; - } - - @Override - public void connect() throws IOException { - } - -} diff --git a/src/test/java/com/android/volley/mock/MockNetwork.java b/src/test/java/com/android/volley/mock/MockNetwork.java deleted file mode 100644 index 207ec63..0000000 --- a/src/test/java/com/android/volley/mock/MockNetwork.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.volley.mock; - -import com.android.volley.Network; -import com.android.volley.NetworkResponse; -import com.android.volley.Request; -import com.android.volley.ServerError; -import com.android.volley.VolleyError; - -public class MockNetwork implements Network { - public final static int ALWAYS_THROW_EXCEPTIONS = -1; - - private int mNumExceptionsToThrow = 0; - private byte[] mDataToReturn = null; - - /** - * @param numExceptionsToThrow number of times to throw an exception or - * {@link #ALWAYS_THROW_EXCEPTIONS} - */ - public void setNumExceptionsToThrow(int numExceptionsToThrow) { - mNumExceptionsToThrow = numExceptionsToThrow; - } - - public void setDataToReturn(byte[] data) { - mDataToReturn = data; - } - - public Request<?> requestHandled = null; - - @Override - public NetworkResponse performRequest(Request<?> request) throws VolleyError { - if (mNumExceptionsToThrow > 0 || mNumExceptionsToThrow == ALWAYS_THROW_EXCEPTIONS) { - if (mNumExceptionsToThrow != ALWAYS_THROW_EXCEPTIONS) { - mNumExceptionsToThrow--; - } - throw new ServerError(); - } - - requestHandled = request; - return new NetworkResponse(mDataToReturn); - } - -} diff --git a/src/test/java/com/android/volley/mock/MockRequest.java b/src/test/java/com/android/volley/mock/MockRequest.java index 9815ea8..6fc26b4 100644 --- a/src/test/java/com/android/volley/mock/MockRequest.java +++ b/src/test/java/com/android/volley/mock/MockRequest.java @@ -22,7 +22,6 @@ import com.android.volley.Response; import com.android.volley.Response.ErrorListener; import com.android.volley.VolleyError; import com.android.volley.utils.CacheTestUtils; - import java.util.HashMap; import java.util.Map; @@ -97,5 +96,4 @@ public class MockRequest extends Request<byte[]> { parseResponse_called = true; return Response.success(response.data, CacheTestUtils.makeRandomCacheEntry(response.data)); } - } diff --git a/src/test/java/com/android/volley/mock/MockResponseDelivery.java b/src/test/java/com/android/volley/mock/MockResponseDelivery.java deleted file mode 100644 index e923c1a..0000000 --- a/src/test/java/com/android/volley/mock/MockResponseDelivery.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.volley.mock; - -import com.android.volley.Request; -import com.android.volley.Response; -import com.android.volley.ResponseDelivery; -import com.android.volley.VolleyError; - -public class MockResponseDelivery implements ResponseDelivery { - - public boolean postResponse_called = false; - public boolean postError_called = false; - public long postResponse_calledNtimes = 0; - - public boolean wasEitherResponseCalled() { - return postResponse_called || postError_called; - } - - public Response<?> responsePosted = null; - @Override - public void postResponse(Request<?> request, Response<?> response) { - postResponse_called = true; - postResponse_calledNtimes++; - responsePosted = response; - } - - @Override - public void postResponse(Request<?> request, Response<?> response, Runnable runnable) { - postResponse_called = true; - postResponse_calledNtimes++; - responsePosted = response; - runnable.run(); - } - - @Override - public void postError(Request<?> request, VolleyError error) { - postError_called = true; - } -} diff --git a/src/test/java/com/android/volley/mock/TestRequest.java b/src/test/java/com/android/volley/mock/TestRequest.java index 16bf79e..f397f01 100644 --- a/src/test/java/com/android/volley/mock/TestRequest.java +++ b/src/test/java/com/android/volley/mock/TestRequest.java @@ -19,7 +19,6 @@ package com.android.volley.mock; import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.Response; - import java.util.HashMap; import java.util.Map; @@ -43,8 +42,7 @@ public class TestRequest { } @Override - protected void deliverResponse(byte[] response) { - } + protected void deliverResponse(byte[] response) {} } /** Test example of a GET request in the deprecated style. */ @@ -78,8 +76,8 @@ public class TestRequest { } /** - * Test example of a POST request in the new style. In the new style, it is possible - * to have a POST with no body. + * Test example of a POST request in the new style. In the new style, it is possible to have a + * POST with no body. */ public static class Post extends Base { public Post() { @@ -103,7 +101,7 @@ public class TestRequest { } /** - * Test example of a PUT request in the new style. In the new style, it is possible to have a + * Test example of a PUT request in the new style. In the new style, it is possible to have a * PUT with no body. */ public static class Put extends Base { diff --git a/src/test/java/com/android/volley/mock/WaitableQueue.java b/src/test/java/com/android/volley/mock/WaitableQueue.java deleted file mode 100644 index 079bbf5..0000000 --- a/src/test/java/com/android/volley/mock/WaitableQueue.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.volley.mock; - -import com.android.volley.NetworkResponse; -import com.android.volley.Request; -import com.android.volley.Response; - -import java.util.concurrent.PriorityBlockingQueue; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -// TODO: the name of this class sucks -@SuppressWarnings("serial") -public class WaitableQueue extends PriorityBlockingQueue<Request<?>> { - private final Request<?> mStopRequest = new MagicStopRequest(); - private final Semaphore mStopEvent = new Semaphore(0); - - // TODO: this isn't really "until empty" it's "until next call to take() after empty" - public void waitUntilEmpty(long timeoutMillis) - throws TimeoutException, InterruptedException { - add(mStopRequest); - if (!mStopEvent.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS)) { - throw new TimeoutException(); - } - } - - @Override - public Request<?> take() throws InterruptedException { - Request<?> item = super.take(); - if (item == mStopRequest) { - mStopEvent.release(); - return take(); - } - return item; - } - - private static class MagicStopRequest extends Request<Object> { - public MagicStopRequest() { - super(Request.Method.GET, "", null); - } - - @Override - public Priority getPriority() { - return Priority.LOW; - } - - @Override - protected Response<Object> parseNetworkResponse(NetworkResponse response) { - return null; - } - - @Override - protected void deliverResponse(Object response) { - } - } -} diff --git a/src/test/java/com/android/volley/toolbox/AdaptedHttpStackTest.java b/src/test/java/com/android/volley/toolbox/AdaptedHttpStackTest.java index 615687d..dbd6535 100644 --- a/src/test/java/com/android/volley/toolbox/AdaptedHttpStackTest.java +++ b/src/test/java/com/android/volley/toolbox/AdaptedHttpStackTest.java @@ -1,11 +1,20 @@ package com.android.volley.toolbox; -import android.util.Pair; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.mockito.Mockito.when; import com.android.volley.Header; import com.android.volley.Request; import com.android.volley.mock.TestRequest; - +import java.io.IOException; +import java.io.InputStream; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; @@ -18,34 +27,16 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import java.io.IOException; -import java.io.InputStream; -import java.net.SocketTimeoutException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.mockito.Mockito.when; - @RunWith(RobolectricTestRunner.class) public class AdaptedHttpStackTest { private static final Request<?> REQUEST = new TestRequest.Get(); private static final Map<String, String> ADDITIONAL_HEADERS = Collections.emptyMap(); - @Mock - private HttpStack mHttpStack; - @Mock - private HttpResponse mHttpResponse; - @Mock - private StatusLine mStatusLine; - @Mock - private HttpEntity mHttpEntity; - @Mock - private InputStream mContent; + @Mock private HttpStack mHttpStack; + @Mock private HttpResponse mHttpResponse; + @Mock private StatusLine mStatusLine; + @Mock private HttpEntity mHttpEntity; + @Mock private InputStream mContent; private AdaptedHttpStack mAdaptedHttpStack; @@ -112,12 +103,14 @@ public class AdaptedHttpStackTest { public void responseWithHeaders() throws Exception { when(mHttpStack.performRequest(REQUEST, ADDITIONAL_HEADERS)).thenReturn(mHttpResponse); when(mStatusLine.getStatusCode()).thenReturn(12345); - when(mHttpResponse.getAllHeaders()).thenReturn(new org.apache.http.Header[] { - new BasicHeader("header1", "value1_B"), - new BasicHeader("header3", "value3"), - new BasicHeader("HEADER2", "value2"), - new BasicHeader("header1", "value1_A") - }); + when(mHttpResponse.getAllHeaders()) + .thenReturn( + new org.apache.http.Header[] { + new BasicHeader("header1", "value1_B"), + new BasicHeader("header3", "value3"), + new BasicHeader("HEADER2", "value2"), + new BasicHeader("header1", "value1_A") + }); com.android.volley.toolbox.HttpResponse response = mAdaptedHttpStack.executeRequest(REQUEST, ADDITIONAL_HEADERS); diff --git a/src/test/java/com/android/volley/toolbox/AndroidAuthenticatorTest.java b/src/test/java/com/android/volley/toolbox/AndroidAuthenticatorTest.java index e878658..982eda2 100644 --- a/src/test/java/com/android/volley/toolbox/AndroidAuthenticatorTest.java +++ b/src/test/java/com/android/volley/toolbox/AndroidAuthenticatorTest.java @@ -16,6 +16,10 @@ package com.android.volley.toolbox; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerFuture; @@ -26,33 +30,30 @@ import android.os.Bundle; import com.android.volley.AuthFailureError; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import static org.mockito.Mockito.*; - @RunWith(RobolectricTestRunner.class) public class AndroidAuthenticatorTest { - private AccountManager mAccountManager; + @Mock private AccountManager mAccountManager; + @Mock private AccountManagerFuture<Bundle> mFuture; private Account mAccount; - private AccountManagerFuture<Bundle> mFuture; private AndroidAuthenticator mAuthenticator; @Before public void setUp() { - mAccountManager = mock(AccountManager.class); - mFuture = mock(AccountManagerFuture.class); + MockitoAnnotations.initMocks(this); mAccount = new Account("coolperson", "cooltype"); mAuthenticator = new AndroidAuthenticator(mAccountManager, mAccount, "cooltype", false); } @Test(expected = AuthFailureError.class) public void failedGetAuthToken() throws Exception { - when(mAccountManager.getAuthToken(mAccount, "cooltype", false, null, null)).thenReturn(mFuture); + when(mAccountManager.getAuthToken(mAccount, "cooltype", false, null, null)) + .thenReturn(mFuture); when(mFuture.getResult()).thenThrow(new AuthenticatorException("sadness!")); mAuthenticator.getAuthToken(); } @@ -62,7 +63,8 @@ public class AndroidAuthenticatorTest { Intent intent = new Intent(); Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); - when(mAccountManager.getAuthToken(mAccount, "cooltype", false, null, null)).thenReturn(mFuture); + when(mAccountManager.getAuthToken(mAccount, "cooltype", false, null, null)) + .thenReturn(mFuture); when(mFuture.getResult()).thenReturn(bundle); when(mFuture.isDone()).thenReturn(true); when(mFuture.isCancelled()).thenReturn(false); @@ -72,7 +74,8 @@ public class AndroidAuthenticatorTest { @Test(expected = AuthFailureError.class) public void missingAuthToken() throws Exception { Bundle bundle = new Bundle(); - when(mAccountManager.getAuthToken(mAccount, "cooltype", false, null, null)).thenReturn(mFuture); + when(mAccountManager.getAuthToken(mAccount, "cooltype", false, null, null)) + .thenReturn(mFuture); when(mFuture.getResult()).thenReturn(bundle); when(mFuture.isDone()).thenReturn(true); when(mFuture.isCancelled()).thenReturn(false); @@ -89,7 +92,8 @@ public class AndroidAuthenticatorTest { public void goodToken() throws Exception { Bundle bundle = new Bundle(); bundle.putString(AccountManager.KEY_AUTHTOKEN, "monkey"); - when(mAccountManager.getAuthToken(mAccount, "cooltype", false, null, null)).thenReturn(mFuture); + when(mAccountManager.getAuthToken(mAccount, "cooltype", false, null, null)) + .thenReturn(mFuture); when(mFuture.getResult()).thenReturn(bundle); when(mFuture.isDone()).thenReturn(true); when(mFuture.isCancelled()).thenReturn(false); diff --git a/src/test/java/com/android/volley/toolbox/BaseHttpStackTest.java b/src/test/java/com/android/volley/toolbox/BaseHttpStackTest.java index 3ae145c..1049ad0 100644 --- a/src/test/java/com/android/volley/toolbox/BaseHttpStackTest.java +++ b/src/test/java/com/android/volley/toolbox/BaseHttpStackTest.java @@ -1,36 +1,32 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; + import com.android.volley.AuthFailureError; import com.android.volley.Header; import com.android.volley.Request; import com.android.volley.mock.TestRequest; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; - import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.TreeMap; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class BaseHttpStackTest { private static final Request<?> REQUEST = new TestRequest.Get(); private static final Map<String, String> ADDITIONAL_HEADERS = Collections.emptyMap(); - @Mock - private InputStream mContent; + @Mock private InputStream mContent; @Before public void setUp() { @@ -39,16 +35,17 @@ public class BaseHttpStackTest { @Test public void legacyRequestWithoutBody() throws Exception { - BaseHttpStack stack = new BaseHttpStack() { - @Override - public HttpResponse executeRequest( - Request<?> request, Map<String, String> additionalHeaders) - throws IOException, AuthFailureError { - assertSame(REQUEST, request); - assertSame(ADDITIONAL_HEADERS, additionalHeaders); - return new HttpResponse(12345, Collections.<Header>emptyList()); - } - }; + BaseHttpStack stack = + new BaseHttpStack() { + @Override + public HttpResponse executeRequest( + Request<?> request, Map<String, String> additionalHeaders) + throws IOException, AuthFailureError { + assertSame(REQUEST, request); + assertSame(ADDITIONAL_HEADERS, additionalHeaders); + return new HttpResponse(12345, Collections.<Header>emptyList()); + } + }; org.apache.http.HttpResponse resp = stack.performRequest(REQUEST, ADDITIONAL_HEADERS); assertEquals(12345, resp.getStatusLine().getStatusCode()); assertEquals(0, resp.getAllHeaders().length); @@ -57,20 +54,18 @@ public class BaseHttpStackTest { @Test public void legacyResponseWithBody() throws Exception { - BaseHttpStack stack = new BaseHttpStack() { - @Override - public HttpResponse executeRequest( - Request<?> request, Map<String, String> additionalHeaders) - throws IOException, AuthFailureError { - assertSame(REQUEST, request); - assertSame(ADDITIONAL_HEADERS, additionalHeaders); - return new HttpResponse( - 12345, - Collections.<Header>emptyList(), - 555, - mContent); - } - }; + BaseHttpStack stack = + new BaseHttpStack() { + @Override + public HttpResponse executeRequest( + Request<?> request, Map<String, String> additionalHeaders) + throws IOException, AuthFailureError { + assertSame(REQUEST, request); + assertSame(ADDITIONAL_HEADERS, additionalHeaders); + return new HttpResponse( + 12345, Collections.<Header>emptyList(), 555, mContent); + } + }; org.apache.http.HttpResponse resp = stack.performRequest(REQUEST, ADDITIONAL_HEADERS); assertEquals(12345, resp.getStatusLine().getStatusCode()); assertEquals(0, resp.getAllHeaders().length); @@ -80,20 +75,21 @@ public class BaseHttpStackTest { @Test public void legacyResponseHeaders() throws Exception { - BaseHttpStack stack = new BaseHttpStack() { - @Override - public HttpResponse executeRequest( - Request<?> request, Map<String, String> additionalHeaders) - throws IOException, AuthFailureError { - assertSame(REQUEST, request); - assertSame(ADDITIONAL_HEADERS, additionalHeaders); - List<Header> headers = new ArrayList<>(); - headers.add(new Header("HeaderA", "ValueA")); - headers.add(new Header("HeaderB", "ValueB_1")); - headers.add(new Header("HeaderB", "ValueB_2")); - return new HttpResponse(12345, headers); - } - }; + BaseHttpStack stack = + new BaseHttpStack() { + @Override + public HttpResponse executeRequest( + Request<?> request, Map<String, String> additionalHeaders) + throws IOException, AuthFailureError { + assertSame(REQUEST, request); + assertSame(ADDITIONAL_HEADERS, additionalHeaders); + List<Header> headers = new ArrayList<>(); + headers.add(new Header("HeaderA", "ValueA")); + headers.add(new Header("HeaderB", "ValueB_1")); + headers.add(new Header("HeaderB", "ValueB_2")); + return new HttpResponse(12345, headers); + } + }; org.apache.http.HttpResponse resp = stack.performRequest(REQUEST, ADDITIONAL_HEADERS); assertEquals(12345, resp.getStatusLine().getStatusCode()); assertEquals(3, resp.getAllHeaders().length); diff --git a/src/test/java/com/android/volley/toolbox/BasicNetworkTest.java b/src/test/java/com/android/volley/toolbox/BasicNetworkTest.java index 7f0d5e2..adf695d 100644 --- a/src/test/java/com/android/volley/toolbox/BasicNetworkTest.java +++ b/src/test/java/com/android/volley/toolbox/BasicNetworkTest.java @@ -16,6 +16,16 @@ package com.android.volley.toolbox; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + import com.android.volley.AuthFailureError; import com.android.volley.Cache.Entry; import com.android.volley.Header; @@ -27,33 +37,22 @@ import com.android.volley.ServerError; import com.android.volley.TimeoutError; import com.android.volley.VolleyError; import com.android.volley.mock.MockHttpStack; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.RobolectricTestRunner; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.SocketTimeoutException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class BasicNetworkTest { @@ -61,14 +60,16 @@ public class BasicNetworkTest { @Mock private Request<String> mMockRequest; @Mock private RetryPolicy mMockRetryPolicy; - @Before public void setUp() throws Exception { + @Before + public void setUp() throws Exception { initMocks(this); } - @Test public void headersAndPostParams() throws Exception { + @Test + public void headersAndPostParams() throws Exception { MockHttpStack mockHttpStack = new MockHttpStack(); InputStream responseStream = - new ByteArrayInputStream("foobar".getBytes()); + new ByteArrayInputStream("foobar".getBytes(StandardCharsets.UTF_8)); HttpResponse fakeResponse = new HttpResponse(200, Collections.<Header>emptyList(), 6, responseStream); mockHttpStack.setResponseToReturn(fakeResponse); @@ -81,12 +82,16 @@ public class BasicNetworkTest { httpNetwork.performRequest(request); assertEquals("foo", mockHttpStack.getLastHeaders().get("requestheader")); assertEquals("foobar", mockHttpStack.getLastHeaders().get("If-None-Match")); - assertEquals("Sat, 19 Aug 2017 00:20:02 GMT", + assertEquals( + "Sat, 19 Aug 2017 00:20:02 GMT", mockHttpStack.getLastHeaders().get("If-Modified-Since")); - assertEquals("requestpost=foo&", new String(mockHttpStack.getLastPostBody())); + assertEquals( + "requestpost=foo&", + new String(mockHttpStack.getLastPostBody(), StandardCharsets.UTF_8)); } - @Test public void notModified() throws Exception { + @Test + public void notModified() throws Exception { MockHttpStack mockHttpStack = new MockHttpStack(); List<Header> headers = new ArrayList<>(); headers.add(new Header("ServerKeyA", "ServerValueA")); @@ -94,8 +99,7 @@ public class BasicNetworkTest { headers.add(new Header("SharedKey", "ServerValueShared")); headers.add(new Header("sharedcaseinsensitivekey", "ServerValueShared1")); headers.add(new Header("SharedCaseInsensitiveKey", "ServerValueShared2")); - HttpResponse fakeResponse = - new HttpResponse(HttpURLConnection.HTTP_NOT_MODIFIED, headers); + HttpResponse fakeResponse = new HttpResponse(HttpURLConnection.HTTP_NOT_MODIFIED, headers); mockHttpStack.setResponseToReturn(fakeResponse); BasicNetwork httpNetwork = new BasicNetwork(mockHttpStack); Request<String> request = buildRequest(); @@ -117,11 +121,14 @@ public class BasicNetworkTest { expectedHeaders.add(new Header("SharedCaseInsensitiveKey", "ServerValueShared2")); expectedHeaders.add(new Header("CachedKeyA", "CachedValueA")); expectedHeaders.add(new Header("CachedKeyB", "CachedValueB")); - assertThat(expectedHeaders, containsInAnyOrder( - response.allHeaders.toArray(new Header[response.allHeaders.size()]))); + assertThat( + expectedHeaders, + containsInAnyOrder( + response.allHeaders.toArray(new Header[response.allHeaders.size()]))); } - @Test public void notModified_legacyCache() throws Exception { + @Test + public void notModified_legacyCache() throws Exception { MockHttpStack mockHttpStack = new MockHttpStack(); List<Header> headers = new ArrayList<>(); headers.add(new Header("ServerKeyA", "ServerValueA")); @@ -129,8 +136,7 @@ public class BasicNetworkTest { headers.add(new Header("SharedKey", "ServerValueShared")); headers.add(new Header("sharedcaseinsensitivekey", "ServerValueShared1")); headers.add(new Header("SharedCaseInsensitiveKey", "ServerValueShared2")); - HttpResponse fakeResponse = - new HttpResponse(HttpURLConnection.HTTP_NOT_MODIFIED, headers); + HttpResponse fakeResponse = new HttpResponse(HttpURLConnection.HTTP_NOT_MODIFIED, headers); mockHttpStack.setResponseToReturn(fakeResponse); BasicNetwork httpNetwork = new BasicNetwork(mockHttpStack); Request<String> request = buildRequest(); @@ -152,11 +158,14 @@ public class BasicNetworkTest { expectedHeaders.add(new Header("SharedCaseInsensitiveKey", "ServerValueShared2")); expectedHeaders.add(new Header("CachedKeyA", "CachedValueA")); expectedHeaders.add(new Header("CachedKeyB", "CachedValueB")); - assertThat(expectedHeaders, containsInAnyOrder( - response.allHeaders.toArray(new Header[response.allHeaders.size()]))); + assertThat( + expectedHeaders, + containsInAnyOrder( + response.allHeaders.toArray(new Header[response.allHeaders.size()]))); } - @Test public void socketTimeout() throws Exception { + @Test + public void socketTimeout() throws Exception { MockHttpStack mockHttpStack = new MockHttpStack(); mockHttpStack.setExceptionToThrow(new SocketTimeoutException()); BasicNetwork httpNetwork = new BasicNetwork(mockHttpStack); @@ -172,7 +181,8 @@ public class BasicNetworkTest { verify(mMockRetryPolicy).retry(any(TimeoutError.class)); } - @Test public void noConnection() throws Exception { + @Test + public void noConnection() throws Exception { MockHttpStack mockHttpStack = new MockHttpStack(); mockHttpStack.setExceptionToThrow(new IOException()); BasicNetwork httpNetwork = new BasicNetwork(mockHttpStack); @@ -188,7 +198,8 @@ public class BasicNetworkTest { verify(mMockRetryPolicy, never()).retry(any(VolleyError.class)); } - @Test public void unauthorized() throws Exception { + @Test + public void unauthorized() throws Exception { MockHttpStack mockHttpStack = new MockHttpStack(); HttpResponse fakeResponse = new HttpResponse(401, Collections.<Header>emptyList()); mockHttpStack.setResponseToReturn(fakeResponse); @@ -205,7 +216,8 @@ public class BasicNetworkTest { verify(mMockRetryPolicy).retry(any(AuthFailureError.class)); } - @Test public void forbidden() throws Exception { + @Test + public void forbidden() throws Exception { MockHttpStack mockHttpStack = new MockHttpStack(); HttpResponse fakeResponse = new HttpResponse(403, Collections.<Header>emptyList()); mockHttpStack.setResponseToReturn(fakeResponse); @@ -222,7 +234,8 @@ public class BasicNetworkTest { verify(mMockRetryPolicy).retry(any(AuthFailureError.class)); } - @Test public void redirect() throws Exception { + @Test + public void redirect() throws Exception { for (int i = 300; i <= 399; i++) { MockHttpStack mockHttpStack = new MockHttpStack(); HttpResponse fakeResponse = new HttpResponse(i, Collections.<Header>emptyList()); @@ -242,7 +255,8 @@ public class BasicNetworkTest { } } - @Test public void otherClientError() throws Exception { + @Test + public void otherClientError() throws Exception { for (int i = 400; i <= 499; i++) { if (i == 401 || i == 403) { // covered above. @@ -266,13 +280,13 @@ public class BasicNetworkTest { } } - @Test public void serverError_enableRetries() throws Exception { + @Test + public void serverError_enableRetries() throws Exception { for (int i = 500; i <= 599; i++) { MockHttpStack mockHttpStack = new MockHttpStack(); HttpResponse fakeResponse = new HttpResponse(i, Collections.<Header>emptyList()); mockHttpStack.setResponseToReturn(fakeResponse); - BasicNetwork httpNetwork = - new BasicNetwork(mockHttpStack, new ByteArrayPool(4096)); + BasicNetwork httpNetwork = new BasicNetwork(mockHttpStack, new ByteArrayPool(4096)); Request<String> request = buildRequest(); request.setRetryPolicy(mMockRetryPolicy); request.setShouldRetryServerErrors(true); @@ -288,7 +302,8 @@ public class BasicNetworkTest { } } - @Test public void serverError_disableRetries() throws Exception { + @Test + public void serverError_disableRetries() throws Exception { for (int i = 500; i <= 599; i++) { MockHttpStack mockHttpStack = new MockHttpStack(); HttpResponse fakeResponse = new HttpResponse(i, Collections.<Header>emptyList()); @@ -317,8 +332,7 @@ public class BasicNetworkTest { } @Override - protected void deliverResponse(String response) { - } + protected void deliverResponse(String response) {} @Override public Map<String, String> getHeaders() { diff --git a/src/test/java/com/android/volley/toolbox/ByteArrayPoolTest.java b/src/test/java/com/android/volley/toolbox/ByteArrayPoolTest.java index 661e994..62da207 100644 --- a/src/test/java/com/android/volley/toolbox/ByteArrayPoolTest.java +++ b/src/test/java/com/android/volley/toolbox/ByteArrayPoolTest.java @@ -16,15 +16,15 @@ package com.android.volley.toolbox; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; -import static org.junit.Assert.*; +import org.junit.Test; public class ByteArrayPoolTest { - @Test public void reusesBuffer() { + @Test + public void reusesBuffer() { ByteArrayPool pool = new ByteArrayPool(32); byte[] buf1 = pool.getBuf(16); @@ -40,7 +40,8 @@ public class ByteArrayPoolTest { assertTrue(buf3 != buf4); } - @Test public void obeysSizeLimit() { + @Test + public void obeysSizeLimit() { ByteArrayPool pool = new ByteArrayPool(32); byte[] buf1 = pool.getBuf(16); @@ -61,7 +62,8 @@ public class ByteArrayPoolTest { assertTrue(buf6 != buf1 && buf6 != buf2 && buf6 != buf3); } - @Test public void returnsBufferWithRightSize() { + @Test + public void returnsBufferWithRightSize() { ByteArrayPool pool = new ByteArrayPool(32); byte[] buf1 = pool.getBuf(16); diff --git a/src/test/java/com/android/volley/toolbox/CacheTest.java b/src/test/java/com/android/volley/toolbox/CacheTest.java index dcd8a27..22dae22 100644 --- a/src/test/java/com/android/volley/toolbox/CacheTest.java +++ b/src/test/java/com/android/volley/toolbox/CacheTest.java @@ -16,13 +16,13 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertNotNull; + import com.android.volley.Cache; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import static org.junit.Assert.assertNotNull; - @RunWith(RobolectricTestRunner.class) public class CacheTest { diff --git a/src/test/java/com/android/volley/toolbox/DiskBasedCacheTest.java b/src/test/java/com/android/volley/toolbox/DiskBasedCacheTest.java index 04c071e..fb6392c 100644 --- a/src/test/java/com/android/volley/toolbox/DiskBasedCacheTest.java +++ b/src/test/java/com/android/volley/toolbox/DiskBasedCacheTest.java @@ -16,21 +16,26 @@ package com.android.volley.toolbox; +import static org.hamcrest.Matchers.arrayWithSize; +import static org.hamcrest.Matchers.emptyArray; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + import com.android.volley.Cache; import com.android.volley.Header; import com.android.volley.toolbox.DiskBasedCache.CacheHeader; import com.android.volley.toolbox.DiskBasedCache.CountingInputStream; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.EOFException; @@ -42,38 +47,28 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Random; - -import static org.hamcrest.Matchers.arrayWithSize; -import static org.hamcrest.Matchers.emptyArray; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) -@Config(manifest="src/main/AndroidManifest.xml", sdk=16) +@Config(manifest = "src/main/AndroidManifest.xml", sdk = 16) public class DiskBasedCacheTest { private static final int MAX_SIZE = 1024 * 1024; private Cache cache; - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); - @Rule - public ExpectedException exception = ExpectedException.none(); + @Rule public ExpectedException exception = ExpectedException.none(); @Before public void setup() throws IOException { @@ -280,6 +275,33 @@ public class DiskBasedCacheTest { } @Test + public void testReadHeaderListWithNegativeSize() throws IOException { + // If a cached header list is corrupted and begins with a negative size, + // verify that readHeaderList will throw an IOException. + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DiskBasedCache.writeInt(baos, -1); // negative size + CountingInputStream cis = + new CountingInputStream( + new ByteArrayInputStream(baos.toByteArray()), Integer.MAX_VALUE); + // Expect IOException due to negative size + exception.expect(IOException.class); + DiskBasedCache.readHeaderList(cis); + } + + @Test + public void testReadHeaderListWithGinormousSize() throws IOException { + // If a cached header list is corrupted and begins with 2GB size, verify + // that readHeaderList will throw EOFException rather than OutOfMemoryError. + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DiskBasedCache.writeInt(baos, Integer.MAX_VALUE); // 2GB size + CountingInputStream cis = + new CountingInputStream(new ByteArrayInputStream(baos.toByteArray()), baos.size()); + // Expect EOFException when end of stream is reached + exception.expect(EOFException.class); + DiskBasedCache.readHeaderList(cis); + } + + @Test public void testFileIsDeletedWhenWriteHeaderFails() throws IOException { // Create DataOutputStream that throws IOException OutputStream mockedOutputStream = spy(OutputStream.class); @@ -314,8 +336,7 @@ public class DiskBasedCacheTest { doThrow(IOException.class).when(mockedInputStream).read(); // Create broken cache that fails to read anything - DiskBasedCache broken = - spy(new DiskBasedCache(temporaryFolder.getRoot())); + DiskBasedCache broken = spy(new DiskBasedCache(temporaryFolder.getRoot())); doReturn(mockedInputStream).when(broken).createInputStream(any(File.class)); // Attempt to initialize @@ -379,13 +400,15 @@ public class DiskBasedCacheTest { /* Serialization tests */ - @Test public void testEmptyReadThrowsEOF() throws IOException { - ByteArrayInputStream empty = new ByteArrayInputStream(new byte[]{}); + @Test + public void testEmptyReadThrowsEOF() throws IOException { + ByteArrayInputStream empty = new ByteArrayInputStream(new byte[] {}); exception.expect(EOFException.class); DiskBasedCache.readInt(empty); } - @Test public void serializeInt() throws IOException { + @Test + public void serializeInt() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DiskBasedCache.writeInt(baos, 0); DiskBasedCache.writeInt(baos, 19791214); @@ -400,7 +423,8 @@ public class DiskBasedCacheTest { assertEquals(DiskBasedCache.readInt(bais), Integer.MAX_VALUE); } - @Test public void serializeLong() throws Exception { + @Test + public void serializeLong() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DiskBasedCache.writeLong(baos, 0); DiskBasedCache.writeLong(baos, 31337); @@ -419,7 +443,8 @@ public class DiskBasedCacheTest { assertEquals(DiskBasedCache.readLong(bais), Long.MAX_VALUE); } - @Test public void serializeString() throws Exception { + @Test + public void serializeString() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DiskBasedCache.writeString(baos, ""); DiskBasedCache.writeString(baos, "This is a string."); @@ -431,7 +456,8 @@ public class DiskBasedCacheTest { assertEquals(DiskBasedCache.readString(cis), "ファイカス"); } - @Test public void serializeHeaders() throws Exception { + @Test + public void serializeHeaders() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); List<Header> empty = new ArrayList<>(); DiskBasedCache.writeHeaderList(empty, baos); diff --git a/src/test/java/com/android/volley/toolbox/HttpClientStackTest.java b/src/test/java/com/android/volley/toolbox/HttpClientStackTest.java index 0c417d4..2a451dc 100644 --- a/src/test/java/com/android/volley/toolbox/HttpClientStackTest.java +++ b/src/test/java/com/android/volley/toolbox/HttpClientStackTest.java @@ -16,10 +16,12 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import com.android.volley.Request.Method; import com.android.volley.mock.TestRequest; import com.android.volley.toolbox.HttpClientStack.HttpPatch; - import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpHead; @@ -28,17 +30,15 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpTrace; import org.apache.http.client.methods.HttpUriRequest; - import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import static org.junit.Assert.*; - @RunWith(RobolectricTestRunner.class) public class HttpClientStackTest { - @Test public void createDeprecatedGetRequest() throws Exception { + @Test + public void createDeprecatedGetRequest() throws Exception { TestRequest.DeprecatedGet request = new TestRequest.DeprecatedGet(); assertEquals(request.getMethod(), Method.DEPRECATED_GET_OR_POST); @@ -46,7 +46,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpGet); } - @Test public void createDeprecatedPostRequest() throws Exception { + @Test + public void createDeprecatedPostRequest() throws Exception { TestRequest.DeprecatedPost request = new TestRequest.DeprecatedPost(); assertEquals(request.getMethod(), Method.DEPRECATED_GET_OR_POST); @@ -54,7 +55,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpPost); } - @Test public void createGetRequest() throws Exception { + @Test + public void createGetRequest() throws Exception { TestRequest.Get request = new TestRequest.Get(); assertEquals(request.getMethod(), Method.GET); @@ -62,7 +64,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpGet); } - @Test public void createPostRequest() throws Exception { + @Test + public void createPostRequest() throws Exception { TestRequest.Post request = new TestRequest.Post(); assertEquals(request.getMethod(), Method.POST); @@ -70,7 +73,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpPost); } - @Test public void createPostRequestWithBody() throws Exception { + @Test + public void createPostRequestWithBody() throws Exception { TestRequest.PostWithBody request = new TestRequest.PostWithBody(); assertEquals(request.getMethod(), Method.POST); @@ -78,7 +82,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpPost); } - @Test public void createPutRequest() throws Exception { + @Test + public void createPutRequest() throws Exception { TestRequest.Put request = new TestRequest.Put(); assertEquals(request.getMethod(), Method.PUT); @@ -86,7 +91,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpPut); } - @Test public void createPutRequestWithBody() throws Exception { + @Test + public void createPutRequestWithBody() throws Exception { TestRequest.PutWithBody request = new TestRequest.PutWithBody(); assertEquals(request.getMethod(), Method.PUT); @@ -94,7 +100,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpPut); } - @Test public void createDeleteRequest() throws Exception { + @Test + public void createDeleteRequest() throws Exception { TestRequest.Delete request = new TestRequest.Delete(); assertEquals(request.getMethod(), Method.DELETE); @@ -102,7 +109,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpDelete); } - @Test public void createHeadRequest() throws Exception { + @Test + public void createHeadRequest() throws Exception { TestRequest.Head request = new TestRequest.Head(); assertEquals(request.getMethod(), Method.HEAD); @@ -110,7 +118,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpHead); } - @Test public void createOptionsRequest() throws Exception { + @Test + public void createOptionsRequest() throws Exception { TestRequest.Options request = new TestRequest.Options(); assertEquals(request.getMethod(), Method.OPTIONS); @@ -118,7 +127,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpOptions); } - @Test public void createTraceRequest() throws Exception { + @Test + public void createTraceRequest() throws Exception { TestRequest.Trace request = new TestRequest.Trace(); assertEquals(request.getMethod(), Method.TRACE); @@ -126,7 +136,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpTrace); } - @Test public void createPatchRequest() throws Exception { + @Test + public void createPatchRequest() throws Exception { TestRequest.Patch request = new TestRequest.Patch(); assertEquals(request.getMethod(), Method.PATCH); @@ -134,7 +145,8 @@ public class HttpClientStackTest { assertTrue(httpRequest instanceof HttpPatch); } - @Test public void createPatchRequestWithBody() throws Exception { + @Test + public void createPatchRequestWithBody() throws Exception { TestRequest.PatchWithBody request = new TestRequest.PatchWithBody(); assertEquals(request.getMethod(), Method.PATCH); diff --git a/src/test/java/com/android/volley/toolbox/HttpHeaderParserTest.java b/src/test/java/com/android/volley/toolbox/HttpHeaderParserTest.java index 9ccac05..9b670f9 100644 --- a/src/test/java/com/android/volley/toolbox/HttpHeaderParserTest.java +++ b/src/test/java/com/android/volley/toolbox/HttpHeaderParserTest.java @@ -16,15 +16,14 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import com.android.volley.Cache; import com.android.volley.Header; import com.android.volley.NetworkResponse; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -33,8 +32,10 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; - -import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class HttpHeaderParserTest { @@ -47,12 +48,14 @@ public class HttpHeaderParserTest { private NetworkResponse response; private Map<String, String> headers; - @Before public void setUp() throws Exception { + @Before + public void setUp() throws Exception { headers = new HashMap<String, String>(); response = new NetworkResponse(0, null, headers, false); } - @Test public void parseCacheHeaders_noHeaders() { + @Test + public void parseCacheHeaders_noHeaders() { Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); assertNotNull(entry); @@ -63,7 +66,8 @@ public class HttpHeaderParserTest { assertEquals(0, entry.softTtl); } - @Test public void parseCacheHeaders_headersSet() { + @Test + public void parseCacheHeaders_headersSet() { headers.put("MyCustomHeader", "42"); Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); @@ -74,7 +78,8 @@ public class HttpHeaderParserTest { assertEquals("42", entry.responseHeaders.get("MyCustomHeader")); } - @Test public void parseCacheHeaders_etag() { + @Test + public void parseCacheHeaders_etag() { headers.put("ETag", "Yow!"); Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); @@ -83,7 +88,8 @@ public class HttpHeaderParserTest { assertEquals("Yow!", entry.etag); } - @Test public void parseCacheHeaders_normalExpire() { + @Test + public void parseCacheHeaders_normalExpire() { long now = System.currentTimeMillis(); headers.put("Date", rfc1123Date(now)); headers.put("Last-Modified", rfc1123Date(now - ONE_DAY_MILLIS)); @@ -99,7 +105,8 @@ public class HttpHeaderParserTest { assertTrue(entry.ttl == entry.softTtl); } - @Test public void parseCacheHeaders_expiresInPast() { + @Test + public void parseCacheHeaders_expiresInPast() { long now = System.currentTimeMillis(); headers.put("Date", rfc1123Date(now)); headers.put("Expires", rfc1123Date(now - ONE_HOUR_MILLIS)); @@ -113,7 +120,8 @@ public class HttpHeaderParserTest { assertEquals(0, entry.softTtl); } - @Test public void parseCacheHeaders_serverRelative() { + @Test + public void parseCacheHeaders_serverRelative() { long now = System.currentTimeMillis(); // Set "current" date as one hour in the future @@ -127,7 +135,8 @@ public class HttpHeaderParserTest { assertEquals(entry.softTtl, entry.ttl); } - @Test public void parseCacheHeaders_cacheControlOverridesExpires() { + @Test + public void parseCacheHeaders_cacheControlOverridesExpires() { long now = System.currentTimeMillis(); headers.put("Date", rfc1123Date(now)); headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); @@ -141,7 +150,8 @@ public class HttpHeaderParserTest { assertEquals(entry.softTtl, entry.ttl); } - @Test public void testParseCacheHeaders_staleWhileRevalidate() { + @Test + public void testParseCacheHeaders_staleWhileRevalidate() { long now = System.currentTimeMillis(); headers.put("Date", rfc1123Date(now)); headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); @@ -159,7 +169,8 @@ public class HttpHeaderParserTest { assertEqualsWithin(now + ONE_DAY_MILLIS + ONE_WEEK_MILLIS, entry.ttl, ONE_MINUTE_MILLIS); } - @Test public void parseCacheHeaders_cacheControlNoCache() { + @Test + public void parseCacheHeaders_cacheControlNoCache() { long now = System.currentTimeMillis(); headers.put("Date", rfc1123Date(now)); headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); @@ -170,7 +181,8 @@ public class HttpHeaderParserTest { assertNull(entry); } - @Test public void parseCacheHeaders_cacheControlMustRevalidateNoMaxAge() { + @Test + public void parseCacheHeaders_cacheControlMustRevalidateNoMaxAge() { long now = System.currentTimeMillis(); headers.put("Date", rfc1123Date(now)); headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); @@ -183,7 +195,8 @@ public class HttpHeaderParserTest { assertEquals(entry.softTtl, entry.ttl); } - @Test public void parseCacheHeaders_cacheControlMustRevalidateWithMaxAge() { + @Test + public void parseCacheHeaders_cacheControlMustRevalidateWithMaxAge() { long now = System.currentTimeMillis(); headers.put("Date", rfc1123Date(now)); headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); @@ -196,7 +209,8 @@ public class HttpHeaderParserTest { assertEquals(entry.softTtl, entry.ttl); } - @Test public void parseCacheHeaders_cacheControlMustRevalidateWithMaxAgeAndStale() { + @Test + public void parseCacheHeaders_cacheControlMustRevalidateWithMaxAgeAndStale() { long now = System.currentTimeMillis(); headers.put("Date", rfc1123Date(now)); headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); @@ -205,8 +219,8 @@ public class HttpHeaderParserTest { // - stale-while-revalidate (entry.ttl) indicates that the asset may // continue to be served stale for up to additional 7 days, but this is // ignored in this case because of the must-revalidate header. - headers.put("Cache-Control", - "must-revalidate, max-age=86400, stale-while-revalidate=604800"); + headers.put( + "Cache-Control", "must-revalidate, max-age=86400, stale-while-revalidate=604800"); Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); assertNotNull(entry); @@ -227,7 +241,8 @@ public class HttpHeaderParserTest { // -------------------------- - @Test public void parseCharset() { + @Test + public void parseCharset() { // Like the ones we usually see headers.put("Content-Type", "text/plain; charset=utf-8"); assertEquals("utf-8", HttpHeaderParser.parseCharset(headers)); @@ -269,7 +284,8 @@ public class HttpHeaderParserTest { assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers)); } - @Test public void parseCaseInsensitive() { + @Test + public void parseCaseInsensitive() { long now = System.currentTimeMillis(); List<Header> headers = new ArrayList<>(); @@ -286,7 +302,7 @@ public class HttpHeaderParserTest { assertEquals("Yow!", entry.etag); assertEqualsWithin(now + ONE_DAY_MILLIS, entry.ttl, ONE_MINUTE_MILLIS); assertEquals(entry.softTtl, entry.ttl); - assertEquals("ISO-8859-1", - HttpHeaderParser.parseCharset(HttpHeaderParser.toHeaderMap(headers))); + assertEquals( + "ISO-8859-1", HttpHeaderParser.parseCharset(HttpHeaderParser.toHeaderMap(headers))); } } diff --git a/src/test/java/com/android/volley/toolbox/HurlStackTest.java b/src/test/java/com/android/volley/toolbox/HurlStackTest.java index c8dd6f1..c1fc92d 100644 --- a/src/test/java/com/android/volley/toolbox/HurlStackTest.java +++ b/src/test/java/com/android/volley/toolbox/HurlStackTest.java @@ -16,151 +16,232 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.android.volley.Header; import com.android.volley.Request.Method; -import com.android.volley.mock.MockHttpURLConnection; import com.android.volley.mock.TestRequest; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class HurlStackTest { - private MockHttpURLConnection mMockConnection; - - @Before public void setUp() throws Exception { - mMockConnection = new MockHttpURLConnection(); + @Mock private HttpURLConnection mMockConnection; + private HurlStack mHurlStack; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mMockConnection.getOutputStream()).thenReturn(new ByteArrayOutputStream()); + + mHurlStack = + new HurlStack() { + @Override + protected HttpURLConnection createConnection(URL url) { + return mMockConnection; + } + }; } - @Test public void connectionForDeprecatedGetRequest() throws Exception { + @Test + public void connectionForDeprecatedGetRequest() throws Exception { TestRequest.DeprecatedGet request = new TestRequest.DeprecatedGet(); assertEquals(request.getMethod(), Method.DEPRECATED_GET_OR_POST); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("GET", mMockConnection.getRequestMethod()); - assertFalse(mMockConnection.getDoOutput()); + verify(mMockConnection, never()).setRequestMethod(anyString()); + verify(mMockConnection, never()).setDoOutput(true); } - @Test public void connectionForDeprecatedPostRequest() throws Exception { + @Test + public void connectionForDeprecatedPostRequest() throws Exception { TestRequest.DeprecatedPost request = new TestRequest.DeprecatedPost(); assertEquals(request.getMethod(), Method.DEPRECATED_GET_OR_POST); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("POST", mMockConnection.getRequestMethod()); - assertTrue(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("POST"); + verify(mMockConnection).setDoOutput(true); } - @Test public void connectionForGetRequest() throws Exception { + @Test + public void connectionForGetRequest() throws Exception { TestRequest.Get request = new TestRequest.Get(); assertEquals(request.getMethod(), Method.GET); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("GET", mMockConnection.getRequestMethod()); - assertFalse(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("GET"); + verify(mMockConnection, never()).setDoOutput(true); } - @Test public void connectionForPostRequest() throws Exception { + @Test + public void connectionForPostRequest() throws Exception { TestRequest.Post request = new TestRequest.Post(); assertEquals(request.getMethod(), Method.POST); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("POST", mMockConnection.getRequestMethod()); - assertFalse(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("POST"); + verify(mMockConnection, never()).setDoOutput(true); } - @Test public void connectionForPostWithBodyRequest() throws Exception { + @Test + public void connectionForPostWithBodyRequest() throws Exception { TestRequest.PostWithBody request = new TestRequest.PostWithBody(); assertEquals(request.getMethod(), Method.POST); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("POST", mMockConnection.getRequestMethod()); - assertTrue(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("POST"); + verify(mMockConnection).setDoOutput(true); } - @Test public void connectionForPutRequest() throws Exception { + @Test + public void connectionForPutRequest() throws Exception { TestRequest.Put request = new TestRequest.Put(); assertEquals(request.getMethod(), Method.PUT); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("PUT", mMockConnection.getRequestMethod()); - assertFalse(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("PUT"); + verify(mMockConnection, never()).setDoOutput(true); } - @Test public void connectionForPutWithBodyRequest() throws Exception { + @Test + public void connectionForPutWithBodyRequest() throws Exception { TestRequest.PutWithBody request = new TestRequest.PutWithBody(); assertEquals(request.getMethod(), Method.PUT); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("PUT", mMockConnection.getRequestMethod()); - assertTrue(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("PUT"); + verify(mMockConnection).setDoOutput(true); } - @Test public void connectionForDeleteRequest() throws Exception { + @Test + public void connectionForDeleteRequest() throws Exception { TestRequest.Delete request = new TestRequest.Delete(); assertEquals(request.getMethod(), Method.DELETE); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("DELETE", mMockConnection.getRequestMethod()); - assertFalse(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("DELETE"); + verify(mMockConnection, never()).setDoOutput(true); } - @Test public void connectionForHeadRequest() throws Exception { + @Test + public void connectionForHeadRequest() throws Exception { TestRequest.Head request = new TestRequest.Head(); assertEquals(request.getMethod(), Method.HEAD); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("HEAD", mMockConnection.getRequestMethod()); - assertFalse(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("HEAD"); + verify(mMockConnection, never()).setDoOutput(true); } - @Test public void connectionForOptionsRequest() throws Exception { + @Test + public void connectionForOptionsRequest() throws Exception { TestRequest.Options request = new TestRequest.Options(); assertEquals(request.getMethod(), Method.OPTIONS); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("OPTIONS", mMockConnection.getRequestMethod()); - assertFalse(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("OPTIONS"); + verify(mMockConnection, never()).setDoOutput(true); } - @Test public void connectionForTraceRequest() throws Exception { + @Test + public void connectionForTraceRequest() throws Exception { TestRequest.Trace request = new TestRequest.Trace(); assertEquals(request.getMethod(), Method.TRACE); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("TRACE", mMockConnection.getRequestMethod()); - assertFalse(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("TRACE"); + verify(mMockConnection, never()).setDoOutput(true); } - @Test public void connectionForPatchRequest() throws Exception { + @Test + public void connectionForPatchRequest() throws Exception { TestRequest.Patch request = new TestRequest.Patch(); assertEquals(request.getMethod(), Method.PATCH); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("PATCH", mMockConnection.getRequestMethod()); - assertFalse(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("PATCH"); + verify(mMockConnection, never()).setDoOutput(true); } - @Test public void connectionForPatchWithBodyRequest() throws Exception { + @Test + public void connectionForPatchWithBodyRequest() throws Exception { TestRequest.PatchWithBody request = new TestRequest.PatchWithBody(); assertEquals(request.getMethod(), Method.PATCH); HurlStack.setConnectionParametersForRequest(mMockConnection, request); - assertEquals("PATCH", mMockConnection.getRequestMethod()); - assertTrue(mMockConnection.getDoOutput()); + verify(mMockConnection).setRequestMethod("PATCH"); + verify(mMockConnection).setDoOutput(true); + } + + @Test + public void executeRequestClosesConnection_connectionError() throws Exception { + when(mMockConnection.getResponseCode()).thenThrow(new SocketTimeoutException()); + try { + mHurlStack.executeRequest( + new TestRequest.Get(), Collections.<String, String>emptyMap()); + fail("Should have thrown exception"); + } catch (IOException e) { + verify(mMockConnection).disconnect(); + } + } + + @Test + public void executeRequestClosesConnection_invalidResponseCode() throws Exception { + when(mMockConnection.getResponseCode()).thenReturn(-1); + try { + mHurlStack.executeRequest( + new TestRequest.Get(), Collections.<String, String>emptyMap()); + fail("Should have thrown exception"); + } catch (IOException e) { + verify(mMockConnection).disconnect(); + } + } + + @Test + public void executeRequestClosesConnection_noResponseBody() throws Exception { + when(mMockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_NO_CONTENT); + mHurlStack.executeRequest(new TestRequest.Get(), Collections.<String, String>emptyMap()); + verify(mMockConnection).disconnect(); + } + + @Test + public void executeRequestClosesConnection_hasResponseBody() throws Exception { + when(mMockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); + when(mMockConnection.getInputStream()) + .thenReturn(new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8))); + HttpResponse response = + mHurlStack.executeRequest( + new TestRequest.Get(), Collections.<String, String>emptyMap()); + // Shouldn't be disconnected until the stream is consumed. + verify(mMockConnection, never()).disconnect(); + response.getContent().close(); + verify(mMockConnection).disconnect(); } - @Test public void convertHeaders() { + @Test + public void convertHeaders() { Map<String, List<String>> headers = new HashMap<>(); headers.put(null, Collections.singletonList("Ignored")); headers.put("HeaderA", Collections.singletonList("ValueA")); diff --git a/src/test/java/com/android/volley/toolbox/ImageLoaderTest.java b/src/test/java/com/android/volley/toolbox/ImageLoaderTest.java index 8a19817..59a0b1b 100644 --- a/src/test/java/com/android/volley/toolbox/ImageLoaderTest.java +++ b/src/test/java/com/android/volley/toolbox/ImageLoaderTest.java @@ -16,6 +16,15 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.graphics.Bitmap; import android.widget.ImageView; import com.android.volley.Request; @@ -24,11 +33,9 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.robolectric.RobolectricTestRunner; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.*; - @RunWith(RobolectricTestRunner.class) public class ImageLoaderTest { private RequestQueue mRequestQueue; @@ -69,7 +76,7 @@ public class ImageLoaderTest { // Response callback should be called both times. verify(listener, times(2)).onResponse(any(ImageLoader.ImageContainer.class), eq(true)); // But request should be enqueued only once. - verify(mRequestQueue, times(1)).add(any(Request.class)); + verify(mRequestQueue, times(1)).add(Mockito.<Request<?>>any()); } @Test @@ -78,24 +85,37 @@ public class ImageLoaderTest { ImageLoader.getImageListener(null, -1, -1); mImageLoader.setBatchedResponseDelay(1000); - assertNotNull(ImageLoader.class.getConstructor(RequestQueue.class, - ImageLoader.ImageCache.class)); + assertNotNull( + ImageLoader.class.getConstructor(RequestQueue.class, ImageLoader.ImageCache.class)); - assertNotNull(ImageLoader.class.getMethod("getImageListener", ImageView.class, - int.class, int.class)); + assertNotNull( + ImageLoader.class.getMethod( + "getImageListener", ImageView.class, int.class, int.class)); assertNotNull(ImageLoader.class.getMethod("isCached", String.class, int.class, int.class)); - assertNotNull(ImageLoader.class.getMethod("isCached", String.class, int.class, int.class, - ImageView.ScaleType.class)); - assertNotNull(ImageLoader.class.getMethod("get", String.class, - ImageLoader.ImageListener.class)); - assertNotNull(ImageLoader.class.getMethod("get", String.class, - ImageLoader.ImageListener.class, int.class, int.class)); - assertNotNull(ImageLoader.class.getMethod("get", String.class, - ImageLoader.ImageListener.class, int.class, int.class, ImageView.ScaleType.class)); + assertNotNull( + ImageLoader.class.getMethod( + "isCached", String.class, int.class, int.class, ImageView.ScaleType.class)); + assertNotNull( + ImageLoader.class.getMethod("get", String.class, ImageLoader.ImageListener.class)); + assertNotNull( + ImageLoader.class.getMethod( + "get", + String.class, + ImageLoader.ImageListener.class, + int.class, + int.class)); + assertNotNull( + ImageLoader.class.getMethod( + "get", + String.class, + ImageLoader.ImageListener.class, + int.class, + int.class, + ImageView.ScaleType.class)); assertNotNull(ImageLoader.class.getMethod("setBatchedResponseDelay", int.class)); - assertNotNull(ImageLoader.ImageListener.class.getMethod("onResponse", - ImageLoader.ImageContainer.class, boolean.class)); + assertNotNull( + ImageLoader.ImageListener.class.getMethod( + "onResponse", ImageLoader.ImageContainer.class, boolean.class)); } } - diff --git a/src/test/java/com/android/volley/toolbox/ImageRequestTest.java b/src/test/java/com/android/volley/toolbox/ImageRequestTest.java index a99363e..6b50319 100644 --- a/src/test/java/com/android/volley/toolbox/ImageRequestTest.java +++ b/src/test/java/com/android/volley/toolbox/ImageRequestTest.java @@ -16,28 +16,30 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import com.android.volley.NetworkResponse; import com.android.volley.Response; - +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowBitmapFactory; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import static org.junit.Assert.*; - @RunWith(RobolectricTestRunner.class) public class ImageRequestTest { - @Test public void parseNetworkResponse_resizing() throws Exception { + @Test + public void parseNetworkResponse_resizing() throws Exception { // This is a horrible hack but Robolectric doesn't have a way to provide // width and height hints for decodeByteArray. It works because the byte array // "file:fake" is ASCII encodable and thus the name in Robolectric's fake @@ -45,7 +47,7 @@ public class ImageRequestTest { // "file:" + name in its lookaside map. I write all this because it will // probably break mysteriously at some point and I feel terrible about your // having to debug it. - byte[] jpegBytes = "file:fake".getBytes(); + byte[] jpegBytes = "file:fake".getBytes(StandardCharsets.UTF_8); ShadowBitmapFactory.provideWidthAndHeightHints("fake", 1024, 500); NetworkResponse jpeg = new NetworkResponse(jpegBytes); @@ -73,7 +75,6 @@ public class ImageRequestTest { // No resize verifyResize(jpeg, 0, 0, scalteType, 1024, 500); - // Scale the image uniformly (maintain the image's aspect ratio) so that // both dimensions (width and height) of the image will be equal to or // larger than the corresponding dimension of the view. @@ -98,7 +99,6 @@ public class ImageRequestTest { // No resize verifyResize(jpeg, 0, 0, scalteType, 1024, 500); - // Scale in X and Y independently, so that src matches dst exactly. This // may change the aspect ratio of the src. scalteType = ScaleType.FIT_XY; @@ -123,10 +123,15 @@ public class ImageRequestTest { verifyResize(jpeg, 0, 0, scalteType, 1024, 500); } - private void verifyResize(NetworkResponse networkResponse, int maxWidth, int maxHeight, - ScaleType scaleType, int expectedWidth, int expectedHeight) { - ImageRequest request = new ImageRequest("", null, maxWidth, maxHeight, scaleType, - Config.RGB_565, null); + private void verifyResize( + NetworkResponse networkResponse, + int maxWidth, + int maxHeight, + ScaleType scaleType, + int expectedWidth, + int expectedHeight) { + ImageRequest request = + new ImageRequest("", null, maxWidth, maxHeight, scaleType, Config.RGB_565, null); Response<Bitmap> response = request.parseNetworkResponse(networkResponse); assertNotNull(response); assertTrue(response.isSuccess()); @@ -136,7 +141,8 @@ public class ImageRequestTest { assertEquals(expectedHeight, bitmap.getHeight()); } - @Test public void findBestSampleSize() { + @Test + public void findBestSampleSize() { // desired == actual == 1 assertEquals(1, ImageRequest.findBestSampleSize(100, 150, 100, 150)); @@ -164,11 +170,23 @@ public class ImageRequestTest { @Test public void publicMethods() throws Exception { // Catch-all test to find API-breaking changes. - assertNotNull(ImageRequest.class.getConstructor(String.class, Response.Listener.class, - int.class, int.class, Bitmap.Config.class, Response.ErrorListener.class)); - assertNotNull(ImageRequest.class.getConstructor(String.class, Response.Listener.class, - int.class, int.class, ImageView.ScaleType.class, Bitmap.Config.class, - Response.ErrorListener.class)); + assertNotNull( + ImageRequest.class.getConstructor( + String.class, + Response.Listener.class, + int.class, + int.class, + Bitmap.Config.class, + Response.ErrorListener.class)); + assertNotNull( + ImageRequest.class.getConstructor( + String.class, + Response.Listener.class, + int.class, + int.class, + ImageView.ScaleType.class, + Bitmap.Config.class, + Response.ErrorListener.class)); assertEquals(ImageRequest.DEFAULT_IMAGE_TIMEOUT_MS, 1000); assertEquals(ImageRequest.DEFAULT_IMAGE_MAX_RETRIES, 2); assertEquals(ImageRequest.DEFAULT_IMAGE_BACKOFF_MULT, 2f, 0); diff --git a/src/test/java/com/android/volley/toolbox/JsonRequestCharsetTest.java b/src/test/java/com/android/volley/toolbox/JsonRequestCharsetTest.java index db6f648..70bb2ea 100644 --- a/src/test/java/com/android/volley/toolbox/JsonRequestCharsetTest.java +++ b/src/test/java/com/android/volley/toolbox/JsonRequestCharsetTest.java @@ -16,44 +16,41 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import com.android.volley.NetworkResponse; import com.android.volley.Response; -import com.android.volley.toolbox.JsonArrayRequest; -import com.android.volley.toolbox.JsonObjectRequest; - +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; import org.json.JSONArray; import org.json.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import java.lang.Exception; -import java.lang.String; -import java.nio.charset.Charset; -import java.util.HashMap; -import java.util.Map; - -import static org.junit.Assert.*; - @RunWith(RobolectricTestRunner.class) public class JsonRequestCharsetTest { - /** - * String in Czech - "Retezec v cestine." - */ + /** String in Czech - "Retezec v cestine." */ private static final String TEXT_VALUE = "\u0158et\u011bzec v \u010de\u0161tin\u011b."; + private static final String TEXT_NAME = "text"; private static final int TEXT_INDEX = 0; /** - * Copyright symbol has different encoding in utf-8 and ISO-8859-1, - * and it doesn't exists in ISO-8859-2 + * Copyright symbol has different encoding in utf-8 and ISO-8859-1, and it doesn't exists in + * ISO-8859-2 */ private static final String COPY_VALUE = "\u00a9"; + private static final String COPY_NAME = "copyright"; private static final int COPY_INDEX = 1; - @Test public void defaultCharsetJsonObject() throws Exception { + @Test + public void defaultCharsetJsonObject() throws Exception { // UTF-8 is default charset for JSON byte[] data = jsonObjectString().getBytes(Charset.forName("UTF-8")); NetworkResponse network = new NetworkResponse(data); @@ -66,7 +63,8 @@ public class JsonRequestCharsetTest { assertEquals(COPY_VALUE, objectResponse.result.getString(COPY_NAME)); } - @Test public void defaultCharsetJsonArray() throws Exception { + @Test + public void defaultCharsetJsonArray() throws Exception { // UTF-8 is default charset for JSON byte[] data = jsonArrayString().getBytes(Charset.forName("UTF-8")); NetworkResponse network = new NetworkResponse(data); @@ -79,7 +77,8 @@ public class JsonRequestCharsetTest { assertEquals(COPY_VALUE, arrayResponse.result.getString(COPY_INDEX)); } - @Test public void specifiedCharsetJsonObject() throws Exception { + @Test + public void specifiedCharsetJsonObject() throws Exception { byte[] data = jsonObjectString().getBytes(Charset.forName("ISO-8859-1")); Map<String, String> headers = new HashMap<String, String>(); headers.put("Content-Type", "application/json; charset=iso-8859-1"); @@ -89,11 +88,12 @@ public class JsonRequestCharsetTest { assertNotNull(objectResponse); assertTrue(objectResponse.isSuccess()); - //don't check the text in Czech, ISO-8859-1 doesn't support some Czech characters + // don't check the text in Czech, ISO-8859-1 doesn't support some Czech characters assertEquals(COPY_VALUE, objectResponse.result.getString(COPY_NAME)); } - @Test public void specifiedCharsetJsonArray() throws Exception { + @Test + public void specifiedCharsetJsonArray() throws Exception { byte[] data = jsonArrayString().getBytes(Charset.forName("ISO-8859-2")); Map<String, String> headers = new HashMap<String, String>(); headers.put("Content-Type", "application/json; charset=iso-8859-2"); diff --git a/src/test/java/com/android/volley/toolbox/JsonRequestTest.java b/src/test/java/com/android/volley/toolbox/JsonRequestTest.java index e39c8c8..44c0ad9 100644 --- a/src/test/java/com/android/volley/toolbox/JsonRequestTest.java +++ b/src/test/java/com/android/volley/toolbox/JsonRequestTest.java @@ -16,6 +16,8 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertNotNull; + import com.android.volley.Response; import org.json.JSONArray; import org.json.JSONObject; @@ -23,27 +25,49 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import static org.junit.Assert.assertNotNull; - @RunWith(RobolectricTestRunner.class) public class JsonRequestTest { @Test public void publicMethods() throws Exception { // Catch-all test to find API-breaking changes. - assertNotNull(JsonRequest.class.getConstructor(String.class, String.class, - Response.Listener.class, Response.ErrorListener.class)); - assertNotNull(JsonRequest.class.getConstructor(int.class, String.class, String.class, - Response.Listener.class, Response.ErrorListener.class)); + assertNotNull( + JsonRequest.class.getConstructor( + String.class, + String.class, + Response.Listener.class, + Response.ErrorListener.class)); + assertNotNull( + JsonRequest.class.getConstructor( + int.class, + String.class, + String.class, + Response.Listener.class, + Response.ErrorListener.class)); - assertNotNull(JsonArrayRequest.class.getConstructor(String.class, - Response.Listener.class, Response.ErrorListener.class)); - assertNotNull(JsonArrayRequest.class.getConstructor(int.class, String.class, JSONArray.class, - Response.Listener.class, Response.ErrorListener.class)); + assertNotNull( + JsonArrayRequest.class.getConstructor( + String.class, Response.Listener.class, Response.ErrorListener.class)); + assertNotNull( + JsonArrayRequest.class.getConstructor( + int.class, + String.class, + JSONArray.class, + Response.Listener.class, + Response.ErrorListener.class)); - assertNotNull(JsonObjectRequest.class.getConstructor(String.class, JSONObject.class, - Response.Listener.class, Response.ErrorListener.class)); - assertNotNull(JsonObjectRequest.class.getConstructor(int.class, String.class, - JSONObject.class, Response.Listener.class, Response.ErrorListener.class)); + assertNotNull( + JsonObjectRequest.class.getConstructor( + String.class, + JSONObject.class, + Response.Listener.class, + Response.ErrorListener.class)); + assertNotNull( + JsonObjectRequest.class.getConstructor( + int.class, + String.class, + JSONObject.class, + Response.Listener.class, + Response.ErrorListener.class)); } } diff --git a/src/test/java/com/android/volley/toolbox/NetworkImageViewTest.java b/src/test/java/com/android/volley/toolbox/NetworkImageViewTest.java index 055005f..af8fad9 100644 --- a/src/test/java/com/android/volley/toolbox/NetworkImageViewTest.java +++ b/src/test/java/com/android/volley/toolbox/NetworkImageViewTest.java @@ -16,31 +16,34 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import android.content.Context; import android.util.AttributeSet; import android.view.ViewGroup.LayoutParams; import android.widget.ImageView.ScaleType; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RuntimeEnvironment; import org.robolectric.RobolectricTestRunner; - -import static org.junit.Assert.*; +import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class NetworkImageViewTest { private NetworkImageView mNIV; private MockImageLoader mMockImageLoader; - @Before public void setUp() throws Exception { + @Before + public void setUp() throws Exception { mMockImageLoader = new MockImageLoader(); mNIV = new NetworkImageView(RuntimeEnvironment.application); } - @Test public void setImageUrl_requestsImage() { - mNIV.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + @Test + public void setImageUrl_requestsImage() { + mNIV.setLayoutParams( + new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); mNIV.setImageUrl("http://foo", mMockImageLoader); assertEquals("http://foo", mMockImageLoader.lastRequestUrl); assertEquals(0, mMockImageLoader.lastMaxWidth); @@ -52,7 +55,7 @@ public class NetworkImageViewTest { // // instrumentation test. Write this test once it's figured out. // } - private class MockImageLoader extends ImageLoader { + private static class MockImageLoader extends ImageLoader { public MockImageLoader() { super(null, null); } @@ -61,8 +64,13 @@ public class NetworkImageViewTest { public int lastMaxWidth; public int lastMaxHeight; - public ImageContainer get(String requestUrl, ImageListener imageListener, int maxWidth, - int maxHeight, ScaleType scaleType) { + @Override + public ImageContainer get( + String requestUrl, + ImageListener imageListener, + int maxWidth, + int maxHeight, + ScaleType scaleType) { lastRequestUrl = requestUrl; lastMaxWidth = maxWidth; lastMaxHeight = maxHeight; @@ -75,10 +83,12 @@ public class NetworkImageViewTest { // Catch-all test to find API-breaking changes. assertNotNull(NetworkImageView.class.getConstructor(Context.class)); assertNotNull(NetworkImageView.class.getConstructor(Context.class, AttributeSet.class)); - assertNotNull(NetworkImageView.class.getConstructor(Context.class, AttributeSet.class, - int.class)); + assertNotNull( + NetworkImageView.class.getConstructor( + Context.class, AttributeSet.class, int.class)); - assertNotNull(NetworkImageView.class.getMethod("setImageUrl", String.class, ImageLoader.class)); + assertNotNull( + NetworkImageView.class.getMethod("setImageUrl", String.class, ImageLoader.class)); assertNotNull(NetworkImageView.class.getMethod("setDefaultImageResId", int.class)); assertNotNull(NetworkImageView.class.getMethod("setErrorImageResId", int.class)); } diff --git a/src/test/java/com/android/volley/toolbox/PoolingByteArrayOutputStreamTest.java b/src/test/java/com/android/volley/toolbox/PoolingByteArrayOutputStreamTest.java index c3bfac7..266edcd 100644 --- a/src/test/java/com/android/volley/toolbox/PoolingByteArrayOutputStreamTest.java +++ b/src/test/java/com/android/volley/toolbox/PoolingByteArrayOutputStreamTest.java @@ -16,36 +16,39 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.util.Arrays; - import org.junit.Test; -import static org.junit.Assert.*; - public class PoolingByteArrayOutputStreamTest { - @Test public void pooledOneBuffer() throws IOException { + @Test + public void pooledOneBuffer() throws IOException { ByteArrayPool pool = new ByteArrayPool(32768); writeOneBuffer(pool); writeOneBuffer(pool); writeOneBuffer(pool); } - @Test public void pooledIndividualWrites() throws IOException { + @Test + public void pooledIndividualWrites() throws IOException { ByteArrayPool pool = new ByteArrayPool(32768); writeBytesIndividually(pool); writeBytesIndividually(pool); writeBytesIndividually(pool); } - @Test public void unpooled() throws IOException { + @Test + public void unpooled() throws IOException { ByteArrayPool pool = new ByteArrayPool(0); writeOneBuffer(pool); writeOneBuffer(pool); writeOneBuffer(pool); } - @Test public void unpooledIndividualWrites() throws IOException { + @Test + public void unpooledIndividualWrites() throws IOException { ByteArrayPool pool = new ByteArrayPool(0); writeBytesIndividually(pool); writeBytesIndividually(pool); diff --git a/src/test/java/com/android/volley/toolbox/RequestFutureTest.java b/src/test/java/com/android/volley/toolbox/RequestFutureTest.java index c8e23e7..5b5c975 100644 --- a/src/test/java/com/android/volley/toolbox/RequestFutureTest.java +++ b/src/test/java/com/android/volley/toolbox/RequestFutureTest.java @@ -16,13 +16,13 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertNotNull; + import com.android.volley.Request; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import static org.junit.Assert.assertNotNull; - @RunWith(RobolectricTestRunner.class) public class RequestFutureTest { diff --git a/src/test/java/com/android/volley/toolbox/RequestQueueTest.java b/src/test/java/com/android/volley/toolbox/RequestQueueTest.java index 1e4b82e..1899b71 100644 --- a/src/test/java/com/android/volley/toolbox/RequestQueueTest.java +++ b/src/test/java/com/android/volley/toolbox/RequestQueueTest.java @@ -16,21 +16,26 @@ package com.android.volley.toolbox; -import com.android.volley.*; +import static org.junit.Assert.assertNotNull; + +import com.android.volley.Cache; +import com.android.volley.Network; +import com.android.volley.Request; +import com.android.volley.RequestQueue; +import com.android.volley.ResponseDelivery; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import static org.junit.Assert.assertNotNull; - @RunWith(RobolectricTestRunner.class) public class RequestQueueTest { @Test public void publicMethods() throws Exception { // Catch-all test to find API-breaking changes. - assertNotNull(RequestQueue.class.getConstructor(Cache.class, Network.class, int.class, - ResponseDelivery.class)); + assertNotNull( + RequestQueue.class.getConstructor( + Cache.class, Network.class, int.class, ResponseDelivery.class)); assertNotNull(RequestQueue.class.getConstructor(Cache.class, Network.class, int.class)); assertNotNull(RequestQueue.class.getConstructor(Cache.class, Network.class)); diff --git a/src/test/java/com/android/volley/toolbox/RequestTest.java b/src/test/java/com/android/volley/toolbox/RequestTest.java index 22d2ef2..0911ad6 100644 --- a/src/test/java/com/android/volley/toolbox/RequestTest.java +++ b/src/test/java/com/android/volley/toolbox/RequestTest.java @@ -16,21 +16,28 @@ package com.android.volley.toolbox; -import com.android.volley.*; +import static org.junit.Assert.assertNotNull; + +import com.android.volley.Cache; +import com.android.volley.NetworkResponse; +import com.android.volley.Request; +import com.android.volley.RequestQueue; +import com.android.volley.Response; +import com.android.volley.RetryPolicy; +import com.android.volley.VolleyError; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import static org.junit.Assert.assertNotNull; - @RunWith(RobolectricTestRunner.class) public class RequestTest { @Test public void publicMethods() throws Exception { // Catch-all test to find API-breaking changes. - assertNotNull(Request.class.getConstructor(int.class, String.class, - Response.ErrorListener.class)); + assertNotNull( + Request.class.getConstructor( + int.class, String.class, Response.ErrorListener.class)); assertNotNull(Request.class.getMethod("getMethod")); assertNotNull(Request.class.getMethod("setTag", Object.class)); @@ -61,7 +68,8 @@ public class RequestTest { assertNotNull(Request.class.getMethod("getRetryPolicy")); assertNotNull(Request.class.getMethod("markDelivered")); assertNotNull(Request.class.getMethod("hasHadResponseDelivered")); - assertNotNull(Request.class.getDeclaredMethod("parseNetworkResponse", NetworkResponse.class)); + assertNotNull( + Request.class.getDeclaredMethod("parseNetworkResponse", NetworkResponse.class)); assertNotNull(Request.class.getDeclaredMethod("parseNetworkError", VolleyError.class)); assertNotNull(Request.class.getDeclaredMethod("deliverResponse", Object.class)); assertNotNull(Request.class.getMethod("deliverError", VolleyError.class)); diff --git a/src/test/java/com/android/volley/toolbox/ResponseTest.java b/src/test/java/com/android/volley/toolbox/ResponseTest.java index e830eb5..44438fa 100644 --- a/src/test/java/com/android/volley/toolbox/ResponseTest.java +++ b/src/test/java/com/android/volley/toolbox/ResponseTest.java @@ -16,18 +16,17 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertNotNull; + import com.android.volley.Cache; import com.android.volley.NetworkResponse; import com.android.volley.Response; import com.android.volley.VolleyError; +import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import java.util.Map; - -import static org.junit.Assert.assertNotNull; - @RunWith(RobolectricTestRunner.class) public class ResponseTest { @@ -40,13 +39,16 @@ public class ResponseTest { assertNotNull(Response.Listener.class.getDeclaredMethod("onResponse", Object.class)); - assertNotNull(Response.ErrorListener.class.getDeclaredMethod("onErrorResponse", - VolleyError.class)); + assertNotNull( + Response.ErrorListener.class.getDeclaredMethod( + "onErrorResponse", VolleyError.class)); - assertNotNull(NetworkResponse.class.getConstructor(int.class, byte[].class, Map.class, - boolean.class, long.class)); - assertNotNull(NetworkResponse.class.getConstructor(int.class, byte[].class, Map.class, - boolean.class)); + assertNotNull( + NetworkResponse.class.getConstructor( + int.class, byte[].class, Map.class, boolean.class, long.class)); + assertNotNull( + NetworkResponse.class.getConstructor( + int.class, byte[].class, Map.class, boolean.class)); assertNotNull(NetworkResponse.class.getConstructor(byte[].class)); assertNotNull(NetworkResponse.class.getConstructor(byte[].class, Map.class)); } diff --git a/src/test/java/com/android/volley/toolbox/StringRequestTest.java b/src/test/java/com/android/volley/toolbox/StringRequestTest.java index eadd73f..0ecb06b 100644 --- a/src/test/java/com/android/volley/toolbox/StringRequestTest.java +++ b/src/test/java/com/android/volley/toolbox/StringRequestTest.java @@ -16,22 +16,27 @@ package com.android.volley.toolbox; +import static org.junit.Assert.assertNotNull; + import com.android.volley.Response; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import static org.junit.Assert.assertNotNull; - @RunWith(RobolectricTestRunner.class) public class StringRequestTest { @Test public void publicMethods() throws Exception { // Catch-all test to find API-breaking changes. - assertNotNull(StringRequest.class.getConstructor(String.class, Response.Listener.class, - Response.ErrorListener.class)); - assertNotNull(StringRequest.class.getConstructor(int.class, String.class, - Response.Listener.class, Response.ErrorListener.class)); + assertNotNull( + StringRequest.class.getConstructor( + String.class, Response.Listener.class, Response.ErrorListener.class)); + assertNotNull( + StringRequest.class.getConstructor( + int.class, + String.class, + Response.Listener.class, + Response.ErrorListener.class)); } } diff --git a/src/test/java/com/android/volley/utils/CacheTestUtils.java b/src/test/java/com/android/volley/utils/CacheTestUtils.java index 03a2909..49ab996 100644 --- a/src/test/java/com/android/volley/utils/CacheTestUtils.java +++ b/src/test/java/com/android/volley/utils/CacheTestUtils.java @@ -17,13 +17,13 @@ package com.android.volley.utils; import com.android.volley.Cache; - import java.util.Random; public class CacheTestUtils { /** * Makes a random cache entry. + * * @param data Data to use, or null to use random data * @param isExpired Whether the TTLs should be set such that this entry is expired * @param needsRefresh Whether the TTLs should be set such that this entry needs refresh @@ -45,8 +45,8 @@ public class CacheTestUtils { } /** - * Like {@link #makeRandomCacheEntry(byte[], boolean, boolean)} but - * defaults to an unexpired entry. + * Like {@link #makeRandomCacheEntry(byte[], boolean, boolean)} but defaults to an unexpired + * entry. */ public static Cache.Entry makeRandomCacheEntry(byte[] data) { return makeRandomCacheEntry(data, false, false); diff --git a/src/test/java/com/android/volley/utils/ImmediateResponseDelivery.java b/src/test/java/com/android/volley/utils/ImmediateResponseDelivery.java index 235716d..67e5923 100644 --- a/src/test/java/com/android/volley/utils/ImmediateResponseDelivery.java +++ b/src/test/java/com/android/volley/utils/ImmediateResponseDelivery.java @@ -17,21 +17,21 @@ package com.android.volley.utils; import com.android.volley.ExecutorDelivery; - import java.util.concurrent.Executor; /** - * A ResponseDelivery for testing that immediately delivers responses - * instead of posting back to the main thread. + * A ResponseDelivery for testing that immediately delivers responses instead of posting back to the + * main thread. */ public class ImmediateResponseDelivery extends ExecutorDelivery { public ImmediateResponseDelivery() { - super(new Executor() { - @Override - public void execute(Runnable command) { - command.run(); - } - }); + super( + new Executor() { + @Override + public void execute(Runnable command) { + command.run(); + } + }); } } |