aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/android/volley/AsyncCache.java89
-rw-r--r--src/main/java/com/android/volley/AsyncNetwork.java140
-rw-r--r--src/main/java/com/android/volley/AsyncRequestQueue.java626
-rw-r--r--src/main/java/com/android/volley/AuthFailureError.java56
-rw-r--r--src/main/java/com/android/volley/Cache.java113
-rw-r--r--src/main/java/com/android/volley/CacheDispatcher.java206
-rw-r--r--src/main/java/com/android/volley/ClientError.java34
-rw-r--r--src/main/java/com/android/volley/DefaultRetryPolicy.java95
-rw-r--r--src/main/java/com/android/volley/ExecutorDelivery.java121
-rw-r--r--src/main/java/com/android/volley/Header.java59
-rw-r--r--src/main/java/com/android/volley/Network.java29
-rw-r--r--src/main/java/com/android/volley/NetworkDispatcher.java177
-rw-r--r--src/main/java/com/android/volley/NetworkError.java33
-rw-r--r--src/main/java/com/android/volley/NetworkResponse.java198
-rw-r--r--src/main/java/com/android/volley/NoConnectionError.java29
-rw-r--r--src/main/java/com/android/volley/ParseError.java31
-rw-r--r--src/main/java/com/android/volley/Request.java719
-rw-r--r--src/main/java/com/android/volley/RequestQueue.java342
-rw-r--r--src/main/java/com/android/volley/RequestTask.java15
-rw-r--r--src/main/java/com/android/volley/Response.java84
-rw-r--r--src/main/java/com/android/volley/ResponseDelivery.java31
-rw-r--r--src/main/java/com/android/volley/RetryPolicy.java56
-rw-r--r--src/main/java/com/android/volley/ServerError.java29
-rw-r--r--src/main/java/com/android/volley/TimeoutError.java21
-rw-r--r--src/main/java/com/android/volley/VolleyError.java55
-rw-r--r--src/main/java/com/android/volley/VolleyLog.java182
-rw-r--r--src/main/java/com/android/volley/WaitingRequestManager.java176
-rw-r--r--src/main/java/com/android/volley/cronet/CronetHttpStack.java631
-rw-r--r--src/main/java/com/android/volley/toolbox/AdaptedHttpStack.java78
-rw-r--r--src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java123
-rw-r--r--src/main/java/com/android/volley/toolbox/AsyncHttpStack.java170
-rw-r--r--src/main/java/com/android/volley/toolbox/Authenticator.java32
-rw-r--r--src/main/java/com/android/volley/toolbox/BaseHttpStack.java92
-rw-r--r--src/main/java/com/android/volley/toolbox/BasicAsyncNetwork.java288
-rw-r--r--src/main/java/com/android/volley/toolbox/BasicNetwork.java163
-rw-r--r--src/main/java/com/android/volley/toolbox/ByteArrayPool.java130
-rw-r--r--src/main/java/com/android/volley/toolbox/ClearCacheRequest.java66
-rw-r--r--src/main/java/com/android/volley/toolbox/DiskBasedCache.java677
-rw-r--r--src/main/java/com/android/volley/toolbox/FileSupplier.java24
-rw-r--r--src/main/java/com/android/volley/toolbox/HttpClientStack.java201
-rw-r--r--src/main/java/com/android/volley/toolbox/HttpHeaderParser.java301
-rw-r--r--src/main/java/com/android/volley/toolbox/HttpResponse.java118
-rw-r--r--src/main/java/com/android/volley/toolbox/HttpStack.java47
-rw-r--r--src/main/java/com/android/volley/toolbox/HurlStack.java321
-rw-r--r--src/main/java/com/android/volley/toolbox/ImageLoader.java541
-rw-r--r--src/main/java/com/android/volley/toolbox/ImageRequest.java283
-rw-r--r--src/main/java/com/android/volley/toolbox/JsonArrayRequest.java83
-rw-r--r--src/main/java/com/android/volley/toolbox/JsonObjectRequest.java93
-rw-r--r--src/main/java/com/android/volley/toolbox/JsonRequest.java127
-rw-r--r--src/main/java/com/android/volley/toolbox/NetworkImageView.java332
-rw-r--r--src/main/java/com/android/volley/toolbox/NetworkUtility.java196
-rw-r--r--src/main/java/com/android/volley/toolbox/NoAsyncCache.java37
-rw-r--r--src/main/java/com/android/volley/toolbox/NoCache.java42
-rw-r--r--src/main/java/com/android/volley/toolbox/PoolingByteArrayOutputStream.java92
-rw-r--r--src/main/java/com/android/volley/toolbox/RequestFuture.java159
-rw-r--r--src/main/java/com/android/volley/toolbox/StringRequest.java100
-rw-r--r--src/main/java/com/android/volley/toolbox/Threads.java13
-rw-r--r--src/main/java/com/android/volley/toolbox/UrlRewriter.java29
-rw-r--r--src/main/java/com/android/volley/toolbox/Volley.java118
59 files changed, 0 insertions, 9453 deletions
diff --git a/src/main/java/com/android/volley/AsyncCache.java b/src/main/java/com/android/volley/AsyncCache.java
deleted file mode 100644
index 3cddb4b..0000000
--- a/src/main/java/com/android/volley/AsyncCache.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2020 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;
-
-import androidx.annotation.Nullable;
-
-/** Asynchronous equivalent to the {@link Cache} interface. */
-public abstract class AsyncCache {
-
- public interface OnGetCompleteCallback {
- /**
- * Invoked when the read from the cache is complete.
- *
- * @param entry The entry read from the cache, or null if the read failed or the key did not
- * exist in the cache.
- */
- void onGetComplete(@Nullable Cache.Entry entry);
- }
-
- /**
- * Retrieves an entry from the cache and sends it back through the {@link
- * OnGetCompleteCallback#onGetComplete} function
- *
- * @param key Cache key
- * @param callback Callback that will be notified when the information has been retrieved
- */
- public abstract void get(String key, OnGetCompleteCallback callback);
-
- public interface OnWriteCompleteCallback {
- /** Invoked when the cache operation is complete */
- void onWriteComplete();
- }
-
- /**
- * Writes a {@link Cache.Entry} to the cache, and calls {@link
- * OnWriteCompleteCallback#onWriteComplete} after the operation is finished.
- *
- * @param key Cache key
- * @param entry The entry to be written to the cache
- * @param callback Callback that will be notified when the information has been written
- */
- public abstract void put(String key, Cache.Entry entry, OnWriteCompleteCallback callback);
-
- /**
- * Clears the cache. Deletes all cached files from disk. Calls {@link
- * OnWriteCompleteCallback#onWriteComplete} after the operation is finished.
- */
- public abstract void clear(OnWriteCompleteCallback callback);
-
- /**
- * Initializes the cache and calls {@link OnWriteCompleteCallback#onWriteComplete} after the
- * operation is finished.
- */
- public abstract void initialize(OnWriteCompleteCallback callback);
-
- /**
- * Invalidates an entry in the cache and calls {@link OnWriteCompleteCallback#onWriteComplete}
- * after the operation is finished.
- *
- * @param key Cache key
- * @param fullExpire True to fully expire the entry, false to soft expire
- * @param callback Callback that's invoked once the entry has been invalidated
- */
- public abstract void invalidate(
- String key, boolean fullExpire, OnWriteCompleteCallback callback);
-
- /**
- * Removes a {@link Cache.Entry} from the cache, and calls {@link
- * OnWriteCompleteCallback#onWriteComplete} after the operation is finished.
- *
- * @param key Cache key
- * @param callback Callback that's invoked once the entry has been removed
- */
- public abstract void remove(String key, OnWriteCompleteCallback callback);
-}
diff --git a/src/main/java/com/android/volley/AsyncNetwork.java b/src/main/java/com/android/volley/AsyncNetwork.java
deleted file mode 100644
index ad19c03..0000000
--- a/src/main/java/com/android/volley/AsyncNetwork.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2020 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;
-
-import androidx.annotation.RestrictTo;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.atomic.AtomicReference;
-
-/** An asynchronous implementation of {@link Network} to perform requests. */
-public abstract class AsyncNetwork implements Network {
- private ExecutorService mBlockingExecutor;
- private ExecutorService mNonBlockingExecutor;
- private ScheduledExecutorService mNonBlockingScheduledExecutor;
-
- protected AsyncNetwork() {}
-
- /** Interface for callback to be called after request is processed. */
- public interface OnRequestComplete {
- /** Method to be called after successful network request. */
- void onSuccess(NetworkResponse networkResponse);
-
- /** Method to be called after unsuccessful network request. */
- void onError(VolleyError volleyError);
- }
-
- /**
- * Non-blocking method to perform the specified request.
- *
- * @param request Request to process
- * @param callback to be called once NetworkResponse is received
- */
- public abstract void performRequest(Request<?> request, OnRequestComplete callback);
-
- /**
- * Blocking method to perform network request.
- *
- * @param request Request to process
- * @return response retrieved from the network
- * @throws VolleyError in the event of an error
- */
- @Override
- public NetworkResponse performRequest(Request<?> request) throws VolleyError {
- final CountDownLatch latch = new CountDownLatch(1);
- final AtomicReference<NetworkResponse> response = new AtomicReference<>();
- final AtomicReference<VolleyError> error = new AtomicReference<>();
- performRequest(
- request,
- new OnRequestComplete() {
- @Override
- public void onSuccess(NetworkResponse networkResponse) {
- response.set(networkResponse);
- latch.countDown();
- }
-
- @Override
- public void onError(VolleyError volleyError) {
- error.set(volleyError);
- latch.countDown();
- }
- });
- try {
- latch.await();
- } catch (InterruptedException e) {
- VolleyLog.e(e, "while waiting for CountDownLatch");
- Thread.currentThread().interrupt();
- throw new VolleyError(e);
- }
-
- if (response.get() != null) {
- return response.get();
- } else if (error.get() != null) {
- throw error.get();
- } else {
- throw new VolleyError("Neither response entry was set");
- }
- }
-
- /**
- * This method sets the non blocking executor to be used by the network for non-blocking tasks.
- *
- * <p>This method must be called before performing any requests.
- */
- @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
- public void setNonBlockingExecutor(ExecutorService executor) {
- mNonBlockingExecutor = executor;
- }
-
- /**
- * This method sets the blocking executor to be used by the network for potentially blocking
- * tasks.
- *
- * <p>This method must be called before performing any requests.
- */
- @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
- public void setBlockingExecutor(ExecutorService executor) {
- mBlockingExecutor = executor;
- }
-
- /**
- * This method sets the scheduled executor to be used by the network for non-blocking tasks to
- * be scheduled.
- *
- * <p>This method must be called before performing any requests.
- */
- @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
- public void setNonBlockingScheduledExecutor(ScheduledExecutorService executor) {
- mNonBlockingScheduledExecutor = executor;
- }
-
- /** Gets blocking executor to perform any potentially blocking tasks. */
- protected ExecutorService getBlockingExecutor() {
- return mBlockingExecutor;
- }
-
- /** Gets non-blocking executor to perform any non-blocking tasks. */
- protected ExecutorService getNonBlockingExecutor() {
- return mNonBlockingExecutor;
- }
-
- /** Gets scheduled executor to perform any non-blocking tasks that need to be scheduled. */
- protected ScheduledExecutorService getNonBlockingScheduledExecutor() {
- return mNonBlockingScheduledExecutor;
- }
-}
diff --git a/src/main/java/com/android/volley/AsyncRequestQueue.java b/src/main/java/com/android/volley/AsyncRequestQueue.java
deleted file mode 100644
index 3754866..0000000
--- a/src/main/java/com/android/volley/AsyncRequestQueue.java
+++ /dev/null
@@ -1,626 +0,0 @@
-/*
- * Copyright (C) 2020 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;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import com.android.volley.AsyncCache.OnGetCompleteCallback;
-import com.android.volley.AsyncNetwork.OnRequestComplete;
-import com.android.volley.Cache.Entry;
-import java.net.HttpURLConnection;
-import java.util.Comparator;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.PriorityBlockingQueue;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * An asynchronous request dispatch queue.
- *
- * <p>Add requests to the queue with {@link #add(Request)}. Once completed, responses will be
- * delivered on the main thread (unless a custom {@link ResponseDelivery} has been provided)
- */
-public class AsyncRequestQueue extends RequestQueue {
- /** Default number of blocking threads to start. */
- private static final int DEFAULT_BLOCKING_THREAD_POOL_SIZE = 4;
-
- /**
- * AsyncCache used to retrieve and store responses.
- *
- * <p>{@code null} indicates use of blocking Cache.
- */
- @Nullable private final AsyncCache mAsyncCache;
-
- /** AsyncNetwork used to perform nework requests. */
- private final AsyncNetwork mNetwork;
-
- /** Executor for non-blocking tasks. */
- private ExecutorService mNonBlockingExecutor;
-
- /** Executor to be used for non-blocking tasks that need to be scheduled. */
- private ScheduledExecutorService mNonBlockingScheduledExecutor;
-
- /**
- * Executor for blocking tasks.
- *
- * <p>Some tasks in handling requests may not be easy to implement in a non-blocking way, such
- * as reading or parsing the response data. This executor is used to run these tasks.
- */
- private ExecutorService mBlockingExecutor;
-
- /**
- * This interface may be used by advanced applications to provide custom executors according to
- * their needs. Apps must create ExecutorServices dynamically given a blocking queue rather than
- * providing them directly so that Volley can provide a PriorityQueue which will prioritize
- * requests according to Request#getPriority.
- */
- private ExecutorFactory mExecutorFactory;
-
- /** Manage list of waiting requests and de-duplicate requests with same cache key. */
- private final WaitingRequestManager mWaitingRequestManager = new WaitingRequestManager(this);
-
- /**
- * Sets all the variables, but processing does not begin until {@link #start()} is called.
- *
- * @param cache to use for persisting responses to disk. If an AsyncCache was provided, then
- * this will be a {@link ThrowingCache}
- * @param network to perform HTTP requests
- * @param asyncCache to use for persisting responses to disk. May be null to indicate use of
- * blocking cache
- * @param responseDelivery interface for posting responses and errors
- * @param executorFactory Interface to be used to provide custom executors according to the
- * users needs.
- */
- private AsyncRequestQueue(
- Cache cache,
- AsyncNetwork network,
- @Nullable AsyncCache asyncCache,
- ResponseDelivery responseDelivery,
- ExecutorFactory executorFactory) {
- super(cache, network, /* threadPoolSize= */ 0, responseDelivery);
- mAsyncCache = asyncCache;
- mNetwork = network;
- mExecutorFactory = executorFactory;
- }
-
- /** Sets the executors and initializes the cache. */
- @Override
- public void start() {
- stop(); // Make sure any currently running threads are stopped
-
- // Create blocking / non-blocking executors and set them in the network and stack.
- mNonBlockingExecutor = mExecutorFactory.createNonBlockingExecutor(getBlockingQueue());
- mBlockingExecutor = mExecutorFactory.createBlockingExecutor(getBlockingQueue());
- mNonBlockingScheduledExecutor = mExecutorFactory.createNonBlockingScheduledExecutor();
- mNetwork.setBlockingExecutor(mBlockingExecutor);
- mNetwork.setNonBlockingExecutor(mNonBlockingExecutor);
- mNetwork.setNonBlockingScheduledExecutor(mNonBlockingScheduledExecutor);
-
- mNonBlockingExecutor.execute(
- new Runnable() {
- @Override
- public void run() {
- // This is intentionally blocking, because we don't want to process any
- // requests until the cache is initialized.
- if (mAsyncCache != null) {
- final CountDownLatch latch = new CountDownLatch(1);
- mAsyncCache.initialize(
- new AsyncCache.OnWriteCompleteCallback() {
- @Override
- public void onWriteComplete() {
- latch.countDown();
- }
- });
- try {
- latch.await();
- } catch (InterruptedException e) {
- VolleyLog.e(
- e, "Thread was interrupted while initializing the cache.");
- Thread.currentThread().interrupt();
- throw new RuntimeException(e);
- }
- } else {
- getCache().initialize();
- }
- }
- });
- }
-
- /** Shuts down and nullifies both executors */
- @Override
- public void stop() {
- if (mNonBlockingExecutor != null) {
- mNonBlockingExecutor.shutdownNow();
- mNonBlockingExecutor = null;
- }
- if (mBlockingExecutor != null) {
- mBlockingExecutor.shutdownNow();
- mBlockingExecutor = null;
- }
- if (mNonBlockingScheduledExecutor != null) {
- mNonBlockingScheduledExecutor.shutdownNow();
- mNonBlockingScheduledExecutor = null;
- }
- }
-
- /** Begins the request by sending it to the Cache or Network. */
- @Override
- <T> void beginRequest(Request<T> request) {
- // If the request is uncacheable, send it over the network.
- if (request.shouldCache()) {
- if (mAsyncCache != null) {
- mNonBlockingExecutor.execute(new CacheTask<>(request));
- } else {
- mBlockingExecutor.execute(new CacheTask<>(request));
- }
- } else {
- sendRequestOverNetwork(request);
- }
- }
-
- @Override
- <T> void sendRequestOverNetwork(Request<T> request) {
- mNonBlockingExecutor.execute(new NetworkTask<>(request));
- }
-
- /** Runnable that gets an entry from the cache. */
- private class CacheTask<T> extends RequestTask<T> {
- CacheTask(Request<T> request) {
- super(request);
- }
-
- @Override
- public void run() {
- // If the request has been canceled, don't bother dispatching it.
- if (mRequest.isCanceled()) {
- mRequest.finish("cache-discard-canceled");
- return;
- }
-
- mRequest.addMarker("cache-queue-take");
-
- // Attempt to retrieve this item from cache.
- if (mAsyncCache != null) {
- mAsyncCache.get(
- mRequest.getCacheKey(),
- new OnGetCompleteCallback() {
- @Override
- public void onGetComplete(Entry entry) {
- handleEntry(entry, mRequest);
- }
- });
- } else {
- Entry entry = getCache().get(mRequest.getCacheKey());
- handleEntry(entry, mRequest);
- }
- }
- }
-
- /** Helper method that handles the cache entry after getting it from the Cache. */
- private void handleEntry(final Entry entry, final Request<?> mRequest) {
- if (entry == null) {
- mRequest.addMarker("cache-miss");
- // Cache miss; send off to the network dispatcher.
- if (!mWaitingRequestManager.maybeAddToWaitingRequests(mRequest)) {
- sendRequestOverNetwork(mRequest);
- }
- return;
- }
-
- // If it is completely expired, just send it to the network.
- if (entry.isExpired()) {
- mRequest.addMarker("cache-hit-expired");
- mRequest.setCacheEntry(entry);
- if (!mWaitingRequestManager.maybeAddToWaitingRequests(mRequest)) {
- sendRequestOverNetwork(mRequest);
- }
- return;
- }
-
- // We have a cache hit; parse its data for delivery back to the request.
- mBlockingExecutor.execute(new CacheParseTask<>(mRequest, entry));
- }
-
- private class CacheParseTask<T> extends RequestTask<T> {
- Cache.Entry entry;
-
- CacheParseTask(Request<T> request, Cache.Entry entry) {
- super(request);
- this.entry = entry;
- }
-
- @Override
- public void run() {
- mRequest.addMarker("cache-hit");
- Response<?> response =
- mRequest.parseNetworkResponse(
- new NetworkResponse(
- HttpURLConnection.HTTP_OK,
- entry.data,
- /* notModified= */ false,
- /* networkTimeMs= */ 0,
- entry.allResponseHeaders));
- mRequest.addMarker("cache-hit-parsed");
-
- if (!entry.refreshNeeded()) {
- // Completely unexpired cache hit. Just deliver the response.
- getResponseDelivery().postResponse(mRequest, response);
- } else {
- // Soft-expired cache hit. We can deliver the cached response,
- // but we need to also send the request to the network for
- // refreshing.
- mRequest.addMarker("cache-hit-refresh-needed");
- mRequest.setCacheEntry(entry);
- // Mark the response as intermediate.
- response.intermediate = true;
-
- if (!mWaitingRequestManager.maybeAddToWaitingRequests(mRequest)) {
- // Post the intermediate response back to the user and have
- // the delivery then forward the request along to the network.
- getResponseDelivery()
- .postResponse(
- mRequest,
- response,
- new Runnable() {
- @Override
- public void run() {
- sendRequestOverNetwork(mRequest);
- }
- });
- } else {
- // request has been added to list of waiting requests
- // to receive the network response from the first request once it
- // returns.
- getResponseDelivery().postResponse(mRequest, response);
- }
- }
- }
- }
-
- private class ParseErrorTask<T> extends RequestTask<T> {
- VolleyError volleyError;
-
- ParseErrorTask(Request<T> request, VolleyError volleyError) {
- super(request);
- this.volleyError = volleyError;
- }
-
- @Override
- public void run() {
- VolleyError parsedError = mRequest.parseNetworkError(volleyError);
- getResponseDelivery().postError(mRequest, parsedError);
- mRequest.notifyListenerResponseNotUsable();
- }
- }
-
- /** Runnable that performs the network request */
- private class NetworkTask<T> extends RequestTask<T> {
- NetworkTask(Request<T> request) {
- super(request);
- }
-
- @Override
- public void run() {
- // If the request was cancelled already, do not perform the network request.
- if (mRequest.isCanceled()) {
- mRequest.finish("network-discard-cancelled");
- mRequest.notifyListenerResponseNotUsable();
- return;
- }
-
- final long startTimeMs = SystemClock.elapsedRealtime();
- mRequest.addMarker("network-queue-take");
-
- // TODO: Figure out what to do with traffic stats tags. Can this be pushed to the
- // HTTP stack, or is it no longer feasible to support?
-
- // Perform the network request.
- mNetwork.performRequest(
- mRequest,
- new OnRequestComplete() {
- @Override
- public void onSuccess(final NetworkResponse networkResponse) {
- mRequest.addMarker("network-http-complete");
-
- // If the server returned 304 AND we delivered a response already,
- // we're done -- don't deliver a second identical response.
- if (networkResponse.notModified && mRequest.hasHadResponseDelivered()) {
- mRequest.finish("not-modified");
- mRequest.notifyListenerResponseNotUsable();
- return;
- }
-
- // Parse the response here on the worker thread.
- mBlockingExecutor.execute(
- new NetworkParseTask<>(mRequest, networkResponse));
- }
-
- @Override
- public void onError(final VolleyError volleyError) {
- volleyError.setNetworkTimeMs(
- SystemClock.elapsedRealtime() - startTimeMs);
- mBlockingExecutor.execute(new ParseErrorTask<>(mRequest, volleyError));
- }
- });
- }
- }
-
- /** Runnable that parses a network response. */
- private class NetworkParseTask<T> extends RequestTask<T> {
- NetworkResponse networkResponse;
-
- NetworkParseTask(Request<T> request, NetworkResponse networkResponse) {
- super(request);
- this.networkResponse = networkResponse;
- }
-
- @Override
- public void run() {
- final Response<?> response = mRequest.parseNetworkResponse(networkResponse);
- mRequest.addMarker("network-parse-complete");
-
- // Write to cache if applicable.
- // TODO: Only update cache metadata instead of entire
- // record for 304s.
- if (mRequest.shouldCache() && response.cacheEntry != null) {
- if (mAsyncCache != null) {
- mNonBlockingExecutor.execute(new CachePutTask<>(mRequest, response));
- } else {
- mBlockingExecutor.execute(new CachePutTask<>(mRequest, response));
- }
- } else {
- finishRequest(mRequest, response, /* cached= */ false);
- }
- }
- }
-
- private class CachePutTask<T> extends RequestTask<T> {
- Response<?> response;
-
- CachePutTask(Request<T> request, Response<?> response) {
- super(request);
- this.response = response;
- }
-
- @Override
- public void run() {
- if (mAsyncCache != null) {
- mAsyncCache.put(
- mRequest.getCacheKey(),
- response.cacheEntry,
- new AsyncCache.OnWriteCompleteCallback() {
- @Override
- public void onWriteComplete() {
- finishRequest(mRequest, response, /* cached= */ true);
- }
- });
- } else {
- getCache().put(mRequest.getCacheKey(), response.cacheEntry);
- finishRequest(mRequest, response, /* cached= */ true);
- }
- }
- }
-
- /** Posts response and notifies listener */
- private void finishRequest(Request<?> mRequest, Response<?> response, boolean cached) {
- if (cached) {
- mRequest.addMarker("network-cache-written");
- }
- // Post the response back.
- mRequest.markDelivered();
- getResponseDelivery().postResponse(mRequest, response);
- mRequest.notifyListenerResponseReceived(response);
- }
-
- /**
- * This class may be used by advanced applications to provide custom executors according to
- * their needs. Apps must create ExecutorServices dynamically given a blocking queue rather than
- * providing them directly so that Volley can provide a PriorityQueue which will prioritize
- * requests according to Request#getPriority.
- */
- public abstract static class ExecutorFactory {
- abstract ExecutorService createNonBlockingExecutor(BlockingQueue<Runnable> taskQueue);
-
- abstract ExecutorService createBlockingExecutor(BlockingQueue<Runnable> taskQueue);
-
- abstract ScheduledExecutorService createNonBlockingScheduledExecutor();
- }
-
- /** Provides a BlockingQueue to be used to create executors. */
- private static PriorityBlockingQueue<Runnable> getBlockingQueue() {
- return new PriorityBlockingQueue<>(
- /* initialCapacity= */ 11,
- new Comparator<Runnable>() {
- @Override
- public int compare(Runnable r1, Runnable r2) {
- // Vanilla runnables are prioritized first, then RequestTasks are ordered
- // by the underlying Request.
- if (r1 instanceof RequestTask) {
- if (r2 instanceof RequestTask) {
- return ((RequestTask<?>) r1).compareTo(((RequestTask<?>) r2));
- }
- return 1;
- }
- return r2 instanceof RequestTask ? -1 : 0;
- }
- });
- }
-
- /**
- * Builder is used to build an instance of {@link AsyncRequestQueue} from values configured by
- * the setters.
- */
- public static class Builder {
- @Nullable private AsyncCache mAsyncCache = null;
- private final AsyncNetwork mNetwork;
- @Nullable private Cache mCache = null;
- @Nullable private ExecutorFactory mExecutorFactory = null;
- @Nullable private ResponseDelivery mResponseDelivery = null;
-
- public Builder(AsyncNetwork asyncNetwork) {
- if (asyncNetwork == null) {
- throw new IllegalArgumentException("Network cannot be null");
- }
- mNetwork = asyncNetwork;
- }
-
- /**
- * Sets the executor factory to be used by the AsyncRequestQueue. If this is not called,
- * Volley will create suitable private thread pools.
- */
- public Builder setExecutorFactory(ExecutorFactory executorFactory) {
- mExecutorFactory = executorFactory;
- return this;
- }
-
- /**
- * Sets the response deliver to be used by the AsyncRequestQueue. If this is not called, we
- * will default to creating a new {@link ExecutorDelivery} with the application's main
- * thread.
- */
- public Builder setResponseDelivery(ResponseDelivery responseDelivery) {
- mResponseDelivery = responseDelivery;
- return this;
- }
-
- /** Sets the AsyncCache to be used by the AsyncRequestQueue. */
- public Builder setAsyncCache(AsyncCache asyncCache) {
- mAsyncCache = asyncCache;
- return this;
- }
-
- /** Sets the Cache to be used by the AsyncRequestQueue. */
- public Builder setCache(Cache cache) {
- mCache = cache;
- return this;
- }
-
- /** Provides a default ExecutorFactory to use, if one is never set. */
- private ExecutorFactory getDefaultExecutorFactory() {
- return new ExecutorFactory() {
- @Override
- public ExecutorService createNonBlockingExecutor(
- BlockingQueue<Runnable> taskQueue) {
- return getNewThreadPoolExecutor(
- /* maximumPoolSize= */ 1,
- /* threadNameSuffix= */ "Non-BlockingExecutor",
- taskQueue);
- }
-
- @Override
- public ExecutorService createBlockingExecutor(BlockingQueue<Runnable> taskQueue) {
- return getNewThreadPoolExecutor(
- /* maximumPoolSize= */ DEFAULT_BLOCKING_THREAD_POOL_SIZE,
- /* threadNameSuffix= */ "BlockingExecutor",
- taskQueue);
- }
-
- @Override
- public ScheduledExecutorService createNonBlockingScheduledExecutor() {
- return new ScheduledThreadPoolExecutor(
- /* corePoolSize= */ 0, getThreadFactory("ScheduledExecutor"));
- }
-
- private ThreadPoolExecutor getNewThreadPoolExecutor(
- int maximumPoolSize,
- final String threadNameSuffix,
- BlockingQueue<Runnable> taskQueue) {
- return new ThreadPoolExecutor(
- /* corePoolSize= */ 0,
- /* maximumPoolSize= */ maximumPoolSize,
- /* keepAliveTime= */ 60,
- /* unit= */ TimeUnit.SECONDS,
- taskQueue,
- getThreadFactory(threadNameSuffix));
- }
-
- private ThreadFactory getThreadFactory(final String threadNameSuffix) {
- return new ThreadFactory() {
- @Override
- public Thread newThread(@NonNull Runnable runnable) {
- Thread t = Executors.defaultThreadFactory().newThread(runnable);
- t.setName("Volley-" + threadNameSuffix);
- return t;
- }
- };
- }
- };
- }
-
- public AsyncRequestQueue build() {
- // If neither cache is set by the caller, throw an illegal argument exception.
- if (mCache == null && mAsyncCache == null) {
- throw new IllegalArgumentException("You must set one of the cache objects");
- }
- if (mCache == null) {
- // if no cache is provided, we will provide one that throws
- // UnsupportedOperationExceptions to pass into the parent class.
- mCache = new ThrowingCache();
- }
- if (mResponseDelivery == null) {
- mResponseDelivery = new ExecutorDelivery(new Handler(Looper.getMainLooper()));
- }
- if (mExecutorFactory == null) {
- mExecutorFactory = getDefaultExecutorFactory();
- }
- return new AsyncRequestQueue(
- mCache, mNetwork, mAsyncCache, mResponseDelivery, mExecutorFactory);
- }
- }
-
- /** A cache that throws an error if a method is called. */
- private static class ThrowingCache implements Cache {
- @Override
- public Entry get(String key) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void put(String key, Entry entry) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void initialize() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void invalidate(String key, boolean fullExpire) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void remove(String key) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clear() {
- throw new UnsupportedOperationException();
- }
- }
-}
diff --git a/src/main/java/com/android/volley/AuthFailureError.java b/src/main/java/com/android/volley/AuthFailureError.java
deleted file mode 100644
index fc6417e..0000000
--- a/src/main/java/com/android/volley/AuthFailureError.java
+++ /dev/null
@@ -1,56 +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;
-
-import android.content.Intent;
-
-/** 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(Intent intent) {
- mResolutionIntent = intent;
- }
-
- public AuthFailureError(NetworkResponse response) {
- super(response);
- }
-
- public AuthFailureError(String message) {
- super(message);
- }
-
- public AuthFailureError(String message, Exception reason) {
- super(message, reason);
- }
-
- public Intent getResolutionIntent() {
- return mResolutionIntent;
- }
-
- @Override
- public String getMessage() {
- if (mResolutionIntent != null) {
- return "User needs to (re)enter credentials.";
- }
- return super.getMessage();
- }
-}
diff --git a/src/main/java/com/android/volley/Cache.java b/src/main/java/com/android/volley/Cache.java
deleted file mode 100644
index b8908ac..0000000
--- a/src/main/java/com/android/volley/Cache.java
+++ /dev/null
@@ -1,113 +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;
-
-import androidx.annotation.Nullable;
-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. */
-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
- */
- @Nullable
- Entry get(String key);
-
- /**
- * 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.
- */
- void initialize();
-
- /**
- * Invalidates an entry in the cache.
- *
- * @param key Cache key
- * @param fullExpire True to fully expire the entry, false to soft expire
- */
- void invalidate(String key, boolean fullExpire);
-
- /**
- * Removes an entry from the cache.
- *
- * @param key Cache key
- */
- void remove(String key);
-
- /** Empties the cache. */
- void clear();
-
- /** Data and metadata for an entry returned by the cache. */
- class Entry {
- /** The data returned from cache. */
- public byte[] data;
-
- /** ETag for cache coherency. */
- public String etag;
-
- /** Date of this response as reported by the server. */
- public long serverDate;
-
- /** The last modified date for the requested object. */
- public long lastModified;
-
- /** TTL for this record. */
- public long ttl;
-
- /** Soft TTL for this record. */
- public long softTtl;
-
- /**
- * Response headers as received from server; must be non-null. Should not be mutated
- * directly.
- *
- * <p>Note that if the server returns two headers with the same (case-insensitive) name,
- * this map will only contain the one of them. {@link #allResponseHeaders} may contain all
- * headers if the {@link Cache} implementation supports it.
- */
- public Map<String, String> responseHeaders = Collections.emptyMap();
-
- /**
- * All response headers. May be null depending on the {@link Cache} implementation. Should
- * not be mutated directly.
- */
- public List<Header> allResponseHeaders;
-
- /** True if the entry is expired. */
- public boolean isExpired() {
- return this.ttl < System.currentTimeMillis();
- }
-
- /** True if a refresh is needed from the original data source. */
- public boolean refreshNeeded() {
- 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
deleted file mode 100644
index 1bfc0ea..0000000
--- a/src/main/java/com/android/volley/CacheDispatcher.java
+++ /dev/null
@@ -1,206 +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;
-
-import android.os.Process;
-import androidx.annotation.VisibleForTesting;
-import java.util.concurrent.BlockingQueue;
-
-/**
- * Provides a thread for performing cache triage on a queue of requests.
- *
- * <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 {
-
- private static final boolean DEBUG = VolleyLog.DEBUG;
-
- /** The queue of requests coming in for triage. */
- private final BlockingQueue<Request<?>> mCacheQueue;
-
- /** The queue of requests going out to the network. */
- private final BlockingQueue<Request<?>> mNetworkQueue;
-
- /** The cache to read from. */
- private final Cache mCache;
-
- /** For posting responses. */
- private final ResponseDelivery mDelivery;
-
- /** Used for telling us to die. */
- private volatile boolean mQuit = false;
-
- /** Manage list of waiting requests and de-duplicate requests with same cache key. */
- private final WaitingRequestManager mWaitingRequestManager;
-
- /**
- * 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
- * @param cache Cache interface to use for resolution
- * @param delivery Delivery interface to use for posting responses
- */
- public CacheDispatcher(
- BlockingQueue<Request<?>> cacheQueue,
- BlockingQueue<Request<?>> networkQueue,
- Cache cache,
- ResponseDelivery delivery) {
- mCacheQueue = cacheQueue;
- mNetworkQueue = networkQueue;
- mCache = cache;
- mDelivery = delivery;
- mWaitingRequestManager = new WaitingRequestManager(this, networkQueue, delivery);
- }
-
- /**
- * 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;
- interrupt();
- }
-
- @Override
- public void run() {
- if (DEBUG) VolleyLog.v("start new dispatcher");
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-
- // Make a blocking call to initialize the cache.
- mCache.initialize();
-
- while (true) {
- try {
- processRequest();
- } catch (InterruptedException e) {
- // We may have been interrupted because it was time to quit.
- if (mQuit) {
- Thread.currentThread().interrupt();
- return;
- }
- VolleyLog.e(
- "Ignoring spurious interrupt of CacheDispatcher thread; "
- + "use quit() to terminate it");
- }
- }
- }
-
- // Extracted to its own method to ensure locals have a constrained liveness scope by the GC.
- // This is needed to avoid keeping previous request references alive for an indeterminate amount
- // of time. Update consumer-proguard-rules.pro when modifying this. See also
- // https://github.com/google/volley/issues/114
- private void processRequest() throws InterruptedException {
- // 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");
- request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_STARTED);
-
- try {
- // If the request has been canceled, don't bother dispatching it.
- if (request.isCanceled()) {
- request.finish("cache-discard-canceled");
- return;
- }
-
- // Attempt to retrieve this item from cache.
- Cache.Entry entry = mCache.get(request.getCacheKey());
- if (entry == null) {
- request.addMarker("cache-miss");
- // Cache miss; send off to the network dispatcher.
- if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
- mNetworkQueue.put(request);
- }
- return;
- }
-
- // If it is completely expired, just send it to the network.
- if (entry.isExpired()) {
- request.addMarker("cache-hit-expired");
- request.setCacheEntry(entry);
- if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
- mNetworkQueue.put(request);
- }
- return;
- }
-
- // 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));
- request.addMarker("cache-hit-parsed");
-
- if (!response.isSuccess()) {
- request.addMarker("cache-parsing-failed");
- mCache.invalidate(request.getCacheKey(), true);
- request.setCacheEntry(null);
- if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
- mNetworkQueue.put(request);
- }
- return;
- }
- if (!entry.refreshNeeded()) {
- // Completely unexpired cache hit. Just deliver the response.
- mDelivery.postResponse(request, response);
- } else {
- // Soft-expired cache hit. We can deliver the cached response,
- // but we need to also send the request to the network for
- // refreshing.
- request.addMarker("cache-hit-refresh-needed");
- request.setCacheEntry(entry);
- // Mark the response as intermediate.
- response.intermediate = true;
-
- 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();
- }
- }
- });
- } else {
- // request has been added to list of waiting requests
- // to receive the network response from the first request once it returns.
- mDelivery.postResponse(request, response);
- }
- }
- } finally {
- request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_FINISHED);
- }
- }
-}
diff --git a/src/main/java/com/android/volley/ClientError.java b/src/main/java/com/android/volley/ClientError.java
deleted file mode 100644
index 521b76f..0000000
--- a/src/main/java/com/android/volley/ClientError.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2015 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;
-
-/**
- * Indicates that the server responded with an error response indicating that the client has erred.
- *
- * <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 {
- public ClientError(NetworkResponse networkResponse) {
- super(networkResponse);
- }
-
- public ClientError() {
- super();
- }
-}
diff --git a/src/main/java/com/android/volley/DefaultRetryPolicy.java b/src/main/java/com/android/volley/DefaultRetryPolicy.java
deleted file mode 100644
index 4be6b50..0000000
--- a/src/main/java/com/android/volley/DefaultRetryPolicy.java
+++ /dev/null
@@ -1,95 +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;
-
-/** Default retry policy for requests. */
-public class DefaultRetryPolicy implements RetryPolicy {
- /** The current timeout in milliseconds. */
- private int mCurrentTimeoutMs;
-
- /** The current retry count. */
- private int mCurrentRetryCount;
-
- /** The maximum number of attempts. */
- private final int mMaxNumRetries;
-
- /** The backoff multiplier for the policy. */
- private final float mBackoffMultiplier;
-
- /** The default socket timeout in milliseconds */
- public static final int DEFAULT_TIMEOUT_MS = 2500;
-
- /** The default number of retries */
- public static final int DEFAULT_MAX_RETRIES = 1;
-
- /** The default backoff multiplier */
- public static final float DEFAULT_BACKOFF_MULT = 1f;
-
- /** 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.
- */
- public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) {
- mCurrentTimeoutMs = initialTimeoutMs;
- mMaxNumRetries = maxNumRetries;
- mBackoffMultiplier = backoffMultiplier;
- }
-
- /** Returns the current timeout. */
- @Override
- public int getCurrentTimeout() {
- return mCurrentTimeoutMs;
- }
-
- /** Returns the current retry count. */
- @Override
- public int getCurrentRetryCount() {
- return mCurrentRetryCount;
- }
-
- /** 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 += (int) (mCurrentTimeoutMs * mBackoffMultiplier);
- if (!hasAttemptRemaining()) {
- throw error;
- }
- }
-
- /** 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
deleted file mode 100644
index fd992f9..0000000
--- a/src/main/java/com/android/volley/ExecutorDelivery.java
+++ /dev/null
@@ -1,121 +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;
-
-import android.os.Handler;
-import java.util.concurrent.Executor;
-
-/** 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);
- }
- };
- }
-
- /**
- * Creates a new response delivery interface, mockable version for testing.
- *
- * @param executor For running delivery tasks
- */
- public ExecutorDelivery(Executor executor) {
- mResponsePoster = executor;
- }
-
- @Override
- public void postResponse(Request<?> request, Response<?> response) {
- postResponse(request, response, null);
- }
-
- @Override
- public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
- request.markDelivered();
- request.addMarker("post-response");
- mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
- }
-
- @Override
- public void postError(Request<?> request, VolleyError error) {
- request.addMarker("post-error");
- Response<?> response = Response.error(error);
- mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));
- }
-
- /** A Runnable used for delivering network responses to a listener on the main thread. */
- @SuppressWarnings("rawtypes")
- private static class ResponseDeliveryRunnable implements Runnable {
- private final Request mRequest;
- private final Response mResponse;
- private final Runnable mRunnable;
-
- public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
- mRequest = request;
- mResponse = response;
- mRunnable = runnable;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public void run() {
- // NOTE: If cancel() is called off the thread that we're currently running in (by
- // default, the main thread), we cannot guarantee that deliverResponse()/deliverError()
- // won't be called, since it may be canceled after we check isCanceled() but before we
- // deliver the response. Apps concerned about this guarantee must either call cancel()
- // from the same thread or implement their own guarantee about not invoking their
- // listener after cancel() has been called.
-
- // If this request has canceled, finish it and don't deliver.
- if (mRequest.isCanceled()) {
- mRequest.finish("canceled-at-delivery");
- return;
- }
-
- // Deliver a normal response or error, depending.
- if (mResponse.isSuccess()) {
- mRequest.deliverResponse(mResponse.result);
- } else {
- mRequest.deliverError(mResponse.error);
- }
-
- // If this is an intermediate response, add a marker, otherwise we're done
- // and the request can be finished.
- if (mResponse.intermediate) {
- mRequest.addMarker("intermediate-response");
- } else {
- mRequest.finish("done");
- }
-
- // If we have been provided a post-delivery runnable, run it.
- 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
deleted file mode 100644
index cd9c6ec..0000000
--- a/src/main/java/com/android/volley/Header.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2017 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;
-
-import android.text.TextUtils;
-
-/** An HTTP header. */
-public final class Header {
- private final String mName;
- private final String mValue;
-
- public Header(String name, String value) {
- mName = name;
- mValue = value;
- }
-
- public final String getName() {
- return mName;
- }
-
- public final String getValue() {
- return mValue;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- Header header = (Header) o;
-
- return TextUtils.equals(mName, header.mName) && TextUtils.equals(mValue, header.mValue);
- }
-
- @Override
- public int hashCode() {
- int result = mName.hashCode();
- result = 31 * result + mValue.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return "Header[name=" + mName + ",value=" + mValue + "]";
- }
-}
diff --git a/src/main/java/com/android/volley/Network.java b/src/main/java/com/android/volley/Network.java
deleted file mode 100644
index 16d5858..0000000
--- a/src/main/java/com/android/volley/Network.java
+++ /dev/null
@@ -1,29 +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;
-
-/** 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
- */
- NetworkResponse performRequest(Request<?> request) throws VolleyError;
-}
diff --git a/src/main/java/com/android/volley/NetworkDispatcher.java b/src/main/java/com/android/volley/NetworkDispatcher.java
deleted file mode 100644
index 06057c3..0000000
--- a/src/main/java/com/android/volley/NetworkDispatcher.java
+++ /dev/null
@@ -1,177 +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;
-
-import android.annotation.TargetApi;
-import android.net.TrafficStats;
-import android.os.Build;
-import android.os.Process;
-import android.os.SystemClock;
-import androidx.annotation.VisibleForTesting;
-import java.util.concurrent.BlockingQueue;
-
-/**
- * Provides a thread for performing network dispatch from a queue of requests.
- *
- * <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 {
-
- /** The queue of requests to service. */
- private final BlockingQueue<Request<?>> mQueue;
- /** The network interface for processing requests. */
- private final Network mNetwork;
- /** The cache to write to. */
- private final Cache mCache;
- /** For posting responses and errors. */
- private final ResponseDelivery mDelivery;
- /** Used for telling us to die. */
- private volatile boolean mQuit = false;
-
- /**
- * 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) {
- mQueue = queue;
- mNetwork = network;
- mCache = cache;
- mDelivery = delivery;
- }
-
- /**
- * 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;
- interrupt();
- }
-
- @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
- private void addTrafficStatsTag(Request<?> request) {
- // Tag the request (if API >= 14)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
- }
- }
-
- @Override
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- while (true) {
- try {
- processRequest();
- } catch (InterruptedException e) {
- // We may have been interrupted because it was time to quit.
- if (mQuit) {
- Thread.currentThread().interrupt();
- return;
- }
- VolleyLog.e(
- "Ignoring spurious interrupt of NetworkDispatcher thread; "
- + "use quit() to terminate it");
- }
- }
- }
-
- // Extracted to its own method to ensure locals have a constrained liveness scope by the GC.
- // This is needed to avoid keeping previous request references alive for an indeterminate amount
- // of time. Update consumer-proguard-rules.pro when modifying this. See also
- // https://github.com/google/volley/issues/114
- private void processRequest() throws InterruptedException {
- // Take a request from the queue.
- Request<?> request = mQueue.take();
- processRequest(request);
- }
-
- @VisibleForTesting
- void processRequest(Request<?> request) {
- long startTimeMs = SystemClock.elapsedRealtime();
- request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_STARTED);
- try {
- request.addMarker("network-queue-take");
-
- // If the request was cancelled already, do not perform the
- // network request.
- if (request.isCanceled()) {
- request.finish("network-discard-cancelled");
- request.notifyListenerResponseNotUsable();
- return;
- }
-
- addTrafficStatsTag(request);
-
- // Perform the network request.
- NetworkResponse networkResponse = mNetwork.performRequest(request);
- request.addMarker("network-http-complete");
-
- // If the server returned 304 AND we delivered a response already,
- // we're done -- don't deliver a second identical response.
- if (networkResponse.notModified && request.hasHadResponseDelivered()) {
- request.finish("not-modified");
- request.notifyListenerResponseNotUsable();
- return;
- }
-
- // Parse the response here on the worker thread.
- Response<?> response = request.parseNetworkResponse(networkResponse);
- request.addMarker("network-parse-complete");
-
- // Write to cache if applicable.
- // TODO: Only update cache metadata instead of entire record for 304s.
- if (request.shouldCache() && response.cacheEntry != null) {
- mCache.put(request.getCacheKey(), response.cacheEntry);
- request.addMarker("network-cache-written");
- }
-
- // Post the response back.
- request.markDelivered();
- mDelivery.postResponse(request, response);
- request.notifyListenerResponseReceived(response);
- } catch (VolleyError volleyError) {
- volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
- parseAndDeliverNetworkError(request, volleyError);
- request.notifyListenerResponseNotUsable();
- } catch (Exception e) {
- VolleyLog.e(e, "Unhandled exception %s", e.toString());
- VolleyError volleyError = new VolleyError(e);
- volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
- mDelivery.postError(request, volleyError);
- request.notifyListenerResponseNotUsable();
- } finally {
- request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_FINISHED);
- }
- }
-
- private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
- error = request.parseNetworkError(error);
- mDelivery.postError(request, error);
- }
-}
diff --git a/src/main/java/com/android/volley/NetworkError.java b/src/main/java/com/android/volley/NetworkError.java
deleted file mode 100644
index 6b2b19f..0000000
--- a/src/main/java/com/android/volley/NetworkError.java
+++ /dev/null
@@ -1,33 +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;
-
-/** Indicates that there was a network error when performing a Volley request. */
-@SuppressWarnings("serial")
-public class NetworkError extends VolleyError {
- public NetworkError() {
- super();
- }
-
- public NetworkError(Throwable cause) {
- super(cause);
- }
-
- public NetworkError(NetworkResponse networkResponse) {
- super(networkResponse);
- }
-}
diff --git a/src/main/java/com/android/volley/NetworkResponse.java b/src/main/java/com/android/volley/NetworkResponse.java
deleted file mode 100644
index cfbc371..0000000
--- a/src/main/java/com/android/volley/NetworkResponse.java
+++ /dev/null
@@ -1,198 +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;
-
-import androidx.annotation.Nullable;
-import java.net.HttpURLConnection;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-/** 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.
- */
- @Deprecated
- public NetworkResponse(
- int statusCode,
- byte[] data,
- @Nullable 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,
- @Nullable 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.
- */
- @Deprecated
- public NetworkResponse(
- int statusCode,
- byte[] data,
- @Nullable 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,
- /* 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.
- */
- @Deprecated
- public NetworkResponse(byte[] data, @Nullable Map<String, String> headers) {
- this(
- HttpURLConnection.HTTP_OK,
- data,
- headers,
- /* notModified= */ false,
- /* networkTimeMs= */ 0);
- }
-
- private NetworkResponse(
- int statusCode,
- byte[] data,
- @Nullable Map<String, String> headers,
- @Nullable List<Header> allHeaders,
- boolean notModified,
- long networkTimeMs) {
- this.statusCode = statusCode;
- this.data = data;
- this.headers = headers;
- if (allHeaders == null) {
- this.allHeaders = null;
- } else {
- this.allHeaders = Collections.unmodifiableList(allHeaders);
- }
- this.notModified = notModified;
- this.networkTimeMs = networkTimeMs;
- }
-
- /** The HTTP status code. */
- public final int statusCode;
-
- /** Raw data from this response. */
- public final byte[] data;
-
- /**
- * Response headers.
- *
- * <p>This map is case-insensitive. It should not be mutated directly.
- *
- * <p>Note that if the server returns two headers with the same (case-insensitive) name, this
- * map will only contain the last one. Use {@link #allHeaders} to inspect all headers returned
- * by the server.
- */
- @Nullable public final Map<String, String> headers;
-
- /** All response headers. Must not be mutated directly. */
- @Nullable public final List<Header> allHeaders;
-
- /** True if the server returned a 304 (Not Modified). */
- public final boolean notModified;
-
- /** Network roundtrip time in milliseconds. */
- public final long networkTimeMs;
-
- @Nullable
- private static Map<String, String> toHeaderMap(@Nullable List<Header> allHeaders) {
- if (allHeaders == null) {
- return null;
- }
- if (allHeaders.isEmpty()) {
- return Collections.emptyMap();
- }
- Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- // Later elements in the list take precedence.
- for (Header header : allHeaders) {
- headers.put(header.getName(), header.getValue());
- }
- return headers;
- }
-
- @Nullable
- private static List<Header> toAllHeaderList(@Nullable Map<String, String> headers) {
- if (headers == null) {
- return null;
- }
- if (headers.isEmpty()) {
- return Collections.emptyList();
- }
- List<Header> allHeaders = new ArrayList<>(headers.size());
- for (Map.Entry<String, String> header : headers.entrySet()) {
- allHeaders.add(new Header(header.getKey(), header.getValue()));
- }
- return allHeaders;
- }
-}
diff --git a/src/main/java/com/android/volley/NoConnectionError.java b/src/main/java/com/android/volley/NoConnectionError.java
deleted file mode 100644
index 185eb35..0000000
--- a/src/main/java/com/android/volley/NoConnectionError.java
+++ /dev/null
@@ -1,29 +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;
-
-/** Error indicating that no connection could be established when performing a Volley request. */
-@SuppressWarnings("serial")
-public class NoConnectionError extends NetworkError {
- public NoConnectionError() {
- super();
- }
-
- public NoConnectionError(Throwable reason) {
- super(reason);
- }
-}
diff --git a/src/main/java/com/android/volley/ParseError.java b/src/main/java/com/android/volley/ParseError.java
deleted file mode 100644
index 04a9d58..0000000
--- a/src/main/java/com/android/volley/ParseError.java
+++ /dev/null
@@ -1,31 +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;
-
-/** Indicates that the server's response could not be parsed. */
-@SuppressWarnings("serial")
-public class ParseError extends VolleyError {
- public ParseError() {}
-
- public ParseError(NetworkResponse networkResponse) {
- super(networkResponse);
- }
-
- public ParseError(Throwable cause) {
- super(cause);
- }
-}
diff --git a/src/main/java/com/android/volley/Request.java b/src/main/java/com/android/volley/Request.java
deleted file mode 100644
index b60dc74..0000000
--- a/src/main/java/com/android/volley/Request.java
+++ /dev/null
@@ -1,719 +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;
-
-import android.net.TrafficStats;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.text.TextUtils;
-import androidx.annotation.CallSuper;
-import androidx.annotation.GuardedBy;
-import androidx.annotation.Nullable;
-import com.android.volley.VolleyLog.MarkerLog;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * Base class for all network requests.
- *
- * @param <T> The type of parsed response this request expects.
- */
-public abstract class Request<T> implements Comparable<Request<T>> {
-
- /** Default encoding for POST or PUT parameters. See {@link #getParamsEncoding()}. */
- private static final String DEFAULT_PARAMS_ENCODING = "UTF-8";
-
- /** Supported request methods. */
- public interface Method {
- int DEPRECATED_GET_OR_POST = -1;
- int GET = 0;
- int POST = 1;
- int PUT = 2;
- int DELETE = 3;
- int HEAD = 4;
- int OPTIONS = 5;
- int TRACE = 6;
- int PATCH = 7;
- }
-
- /** Callback to notify when the network request returns. */
- /* package */ interface NetworkRequestCompleteListener {
-
- /** Callback when a network response has been received. */
- void onResponseReceived(Request<?> request, Response<?> response);
-
- /** Callback when request returns from network without valid response. */
- void onNoUsableResponseReceived(Request<?> request);
- }
-
- /** An event log tracing the lifetime of this request; for debugging. */
- private final MarkerLog mEventLog = MarkerLog.ENABLED ? new MarkerLog() : null;
-
- /**
- * Request method of this request. Currently supports GET, POST, PUT, DELETE, HEAD, OPTIONS,
- * TRACE, and PATCH.
- */
- private final int mMethod;
-
- /** URL of this request. */
- private final String mUrl;
-
- /** Default tag for {@link TrafficStats}. */
- private final int mDefaultTrafficStatsTag;
-
- /** Lock to guard state which can be mutated after a request is added to the queue. */
- private final Object mLock = new Object();
-
- /** Listener interface for errors. */
- @Nullable
- @GuardedBy("mLock")
- private Response.ErrorListener mErrorListener;
-
- /** Sequence number of this request, used to enforce FIFO ordering. */
- private Integer mSequence;
-
- /** The request queue this request is associated with. */
- private RequestQueue mRequestQueue;
-
- /** Whether or not responses to this request should be cached. */
- // TODO(#190): Turn this off by default for anything other than GET requests.
- private boolean mShouldCache = true;
-
- /** Whether or not this request has been canceled. */
- @GuardedBy("mLock")
- private boolean mCanceled = false;
-
- /** Whether or not a response has been delivered for this request yet. */
- @GuardedBy("mLock")
- private boolean mResponseDelivered = false;
-
- /** Whether the request should be retried in the event of an HTTP 5xx (server) error. */
- private boolean mShouldRetryServerErrors = false;
-
- /** Whether the request should be retried in the event of a {@link NoConnectionError}. */
- private boolean mShouldRetryConnectionErrors = false;
-
- /** The retry policy for this request. */
- 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.
- */
- @Nullable private Cache.Entry mCacheEntry = null;
-
- /** An opaque token tagging this request; used for bulk cancellation. */
- private Object mTag;
-
- /** Listener that will be notified when a response has been delivered. */
- @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.
- *
- * @deprecated Use {@link #Request(int, String, com.android.volley.Response.ErrorListener)}.
- */
- @Deprecated
- public Request(String url, Response.ErrorListener listener) {
- this(Method.DEPRECATED_GET_OR_POST, url, listener);
- }
-
- /**
- * 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, @Nullable Response.ErrorListener listener) {
- mMethod = method;
- mUrl = url;
- mErrorListener = listener;
- setRetryPolicy(new DefaultRetryPolicy());
-
- mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);
- }
-
- /** 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)}.
- *
- * @return This Request object to allow for chaining.
- */
- public Request<?> setTag(Object tag) {
- mTag = tag;
- return this;
- }
-
- /**
- * Returns this request's tag.
- *
- * @see Request#setTag(Object)
- */
- public Object getTag() {
- return mTag;
- }
-
- /** @return this request's {@link com.android.volley.Response.ErrorListener}. */
- @Nullable
- public Response.ErrorListener getErrorListener() {
- synchronized (mLock) {
- return mErrorListener;
- }
- }
-
- /** @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. */
- private static int findDefaultTrafficStatsTag(String url) {
- if (!TextUtils.isEmpty(url)) {
- Uri uri = Uri.parse(url);
- if (uri != null) {
- String host = uri.getHost();
- if (host != null) {
- return host.hashCode();
- }
- }
- }
- return 0;
- }
-
- /**
- * Sets the retry policy for this request.
- *
- * @return This Request object to allow for chaining.
- */
- public Request<?> setRetryPolicy(RetryPolicy retryPolicy) {
- mRetryPolicy = retryPolicy;
- return this;
- }
-
- /** 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());
- }
- }
-
- /**
- * 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.
- */
- void finish(final String tag) {
- if (mRequestQueue != null) {
- mRequestQueue.finish(this);
- }
- if (MarkerLog.ENABLED) {
- final long threadId = Thread.currentThread().getId();
- if (Looper.myLooper() != Looper.getMainLooper()) {
- // 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(Request.this.toString());
- }
- });
- return;
- }
-
- mEventLog.add(tag, threadId);
- mEventLog.finish(this.toString());
- }
- }
-
- void sendEvent(@RequestQueue.RequestEvent int event) {
- if (mRequestQueue != null) {
- mRequestQueue.sendRequestEvent(this, event);
- }
- }
-
- /**
- * Associates this request with the given queue. The request queue will be notified when this
- * request has finished.
- *
- * @return This Request object to allow for chaining.
- */
- public Request<?> setRequestQueue(RequestQueue requestQueue) {
- mRequestQueue = requestQueue;
- return this;
- }
-
- /**
- * Sets the sequence number of this request. Used by {@link RequestQueue}.
- *
- * @return This Request object to allow for chaining.
- */
- public final Request<?> setSequence(int sequence) {
- mSequence = sequence;
- return this;
- }
-
- /** Returns the sequence number of this request. */
- public final int getSequence() {
- if (mSequence == null) {
- throw new IllegalStateException("getSequence called before setSequence");
- }
- return mSequence;
- }
-
- /** Returns the URL of this request. */
- public String getUrl() {
- return mUrl;
- }
-
- /** Returns the cache key for this request. By default, this is the URL. */
- public String getCacheKey() {
- String url = getUrl();
- // If this is a GET request, just use the URL as the key.
- // For callers using DEPRECATED_GET_OR_POST, we assume the method is GET, which matches
- // legacy behavior where all methods had the same cache key. We can't determine which method
- // will be used because doing so requires calling getPostBody() which is expensive and may
- // throw AuthFailureError.
- // TODO(#190): Remove support for non-GET methods.
- int method = getMethod();
- if (method == Method.GET || method == Method.DEPRECATED_GET_OR_POST) {
- return url;
- }
- return Integer.toString(method) + '-' + url;
- }
-
- /**
- * Annotates this request with an entry retrieved for it from cache. Used for cache coherency
- * support.
- *
- * @return This Request object to allow for chaining.
- */
- public Request<?> setCacheEntry(Cache.Entry entry) {
- mCacheEntry = entry;
- return this;
- }
-
- /** Returns the annotated cache entry, or null if there isn't one. */
- @Nullable
- public Cache.Entry getCacheEntry() {
- return mCacheEntry;
- }
-
- /**
- * 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.
- * </ul>
- *
- * <p>There are no guarantees if both of these conditions aren't met.
- */
- @CallSuper
- public void cancel() {
- synchronized (mLock) {
- mCanceled = true;
- mErrorListener = null;
- }
- }
-
- /** Returns true if this request has been canceled. */
- public boolean isCanceled() {
- synchronized (mLock) {
- return mCanceled;
- }
- }
-
- /**
- * 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 {
- return Collections.emptyMap();
- }
-
- /**
- * 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.
- *
- * @throws AuthFailureError In the event of auth failure
- * @deprecated Use {@link #getParams()} instead.
- */
- @Deprecated
- @Nullable
- protected Map<String, String> getPostParams() throws AuthFailureError {
- return getParams();
- }
-
- /**
- * 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>The string encoding used when converting the URL encoded parameters into a raw byte
- * array.
- * </ol>
- *
- * @deprecated Use {@link #getParamsEncoding()} instead.
- */
- @Deprecated
- protected String getPostParamsEncoding() {
- return getParamsEncoding();
- }
-
- /** @deprecated Use {@link #getBodyContentType()} instead. */
- @Deprecated
- public String getPostBodyContentType() {
- return getBodyContentType();
- }
-
- /**
- * Returns the raw POST body to be sent.
- *
- * @throws AuthFailureError In the event of auth failure
- * @deprecated Use {@link #getBody()} instead.
- */
- @Deprecated
- public byte[] getPostBody() throws AuthFailureError {
- // Note: For compatibility with legacy clients of volley, this implementation must remain
- // here instead of simply calling the getBody() function because this function must
- // call getPostParams() and getPostParamsEncoding() since legacy clients would have
- // overridden these two member functions for POST requests.
- Map<String, String> postParams = getPostParams();
- if (postParams != null && postParams.size() > 0) {
- return encodeParameters(postParams, getPostParamsEncoding());
- }
- return null;
- }
-
- /**
- * 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.
- *
- * @throws AuthFailureError in the event of auth failure
- */
- @Nullable
- protected Map<String, String> getParams() throws AuthFailureError {
- return null;
- }
-
- /**
- * Returns which encoding should be used when converting POST or PUT parameters returned by
- * {@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>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. */
- public String getBodyContentType() {
- return "application/x-www-form-urlencoded; charset=" + getParamsEncoding();
- }
-
- /**
- * Returns the raw POST or PUT body to be sent.
- *
- * <p>By default, the body consists of the request parameters in
- * application/x-www-form-urlencoded format. When overriding this method, consider overriding
- * {@link #getBodyContentType()} as well to match the new body format.
- *
- * @throws AuthFailureError in the event of auth failure
- */
- public byte[] getBody() throws AuthFailureError {
- Map<String, String> params = getParams();
- if (params != null && params.size() > 0) {
- return encodeParameters(params, getParamsEncoding());
- }
- return null;
- }
-
- /** 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 {
- for (Map.Entry<String, String> entry : params.entrySet()) {
- if (entry.getKey() == null || entry.getValue() == null) {
- throw new IllegalArgumentException(
- String.format(
- "Request#getParams() or Request#getPostParams() returned a map "
- + "containing a null key or value: (%s, %s). All keys "
- + "and values must be non-null.",
- entry.getKey(), entry.getValue()));
- }
- encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
- encodedParams.append('=');
- encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
- encodedParams.append('&');
- }
- return encodedParams.toString().getBytes(paramsEncoding);
- } catch (UnsupportedEncodingException uee) {
- throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee);
- }
- }
-
- /**
- * Set whether or not responses to this request should be cached.
- *
- * @return This Request object to allow for chaining.
- */
- public final Request<?> setShouldCache(boolean shouldCache) {
- mShouldCache = shouldCache;
- return this;
- }
-
- /** Returns true if responses to this request should be cached. */
- public final boolean shouldCache() {
- return mShouldCache;
- }
-
- /**
- * Sets whether or not the request should be retried in the event of an HTTP 5xx (server) error.
- *
- * @return This Request object to allow for chaining.
- */
- public final Request<?> setShouldRetryServerErrors(boolean shouldRetryServerErrors) {
- mShouldRetryServerErrors = shouldRetryServerErrors;
- return this;
- }
-
- /**
- * Returns true if this request should be retried in the event of an HTTP 5xx (server) error.
- */
- public final boolean shouldRetryServerErrors() {
- return mShouldRetryServerErrors;
- }
-
- /**
- * Sets whether or not the request should be retried in the event that no connection could be
- * established.
- *
- * @return This Request object to allow for chaining.
- */
- public final Request<?> setShouldRetryConnectionErrors(boolean shouldRetryConnectionErrors) {
- mShouldRetryConnectionErrors = shouldRetryConnectionErrors;
- return this;
- }
-
- /**
- * Returns true if this request should be retried in the event that no connection could be
- * established.
- */
- public final boolean shouldRetryConnectionErrors() {
- return mShouldRetryConnectionErrors;
- }
-
- /**
- * Priority values. Requests will be processed from higher priorities to lower priorities, in
- * FIFO order.
- */
- public enum Priority {
- LOW,
- NORMAL,
- HIGH,
- IMMEDIATE
- }
-
- /** 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.
- */
- public final int getTimeoutMs() {
- return getRetryPolicy().getCurrentTimeout();
- }
-
- /** 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.
- */
- public void markDelivered() {
- synchronized (mLock) {
- mResponseDelivered = true;
- }
- }
-
- /** Returns true if this request has had a response delivered for it. */
- public boolean hasHadResponseDelivered() {
- synchronized (mLock) {
- return mResponseDelivered;
- }
- }
-
- /**
- * 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
- */
- 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'.
- *
- * @param volleyError the error retrieved from the network
- * @return an NetworkError augmented with additional information
- */
- protected VolleyError parseNetworkError(VolleyError volleyError) {
- return volleyError;
- }
-
- /**
- * 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)}
- */
- protected abstract void deliverResponse(T response);
-
- /**
- * Delivers error message to the ErrorListener that the Request was initialized with.
- *
- * @param error Error details
- */
- public void deliverError(VolleyError error) {
- Response.ErrorListener listener;
- synchronized (mLock) {
- listener = mErrorListener;
- }
- if (listener != null) {
- listener.onErrorResponse(error);
- }
- }
-
- /**
- * {@link NetworkRequestCompleteListener} that will receive callbacks when the request returns
- * from the network.
- */
- /* package */ void setNetworkRequestCompleteListener(
- NetworkRequestCompleteListener requestCompleteListener) {
- synchronized (mLock) {
- mRequestCompleteListener = requestCompleteListener;
- }
- }
-
- /**
- * 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) {
- NetworkRequestCompleteListener listener;
- synchronized (mLock) {
- listener = mRequestCompleteListener;
- }
- if (listener != null) {
- listener.onResponseReceived(this, response);
- }
- }
-
- /**
- * 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;
- synchronized (mLock) {
- listener = mRequestCompleteListener;
- }
- if (listener != null) {
- listener.onNoUsableResponseReceived(this);
- }
- }
-
- /**
- * Our comparator sorts from high to low priority, and secondarily by sequence number to provide
- * FIFO ordering.
- */
- @Override
- public int compareTo(Request<T> other) {
- Priority left = this.getPriority();
- Priority right = other.getPriority();
-
- // 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();
- }
-
- @Override
- public String toString() {
- String trafficStatsTag = "0x" + Integer.toHexString(getTrafficStatsTag());
- 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
deleted file mode 100644
index 6db0b1c..0000000
--- a/src/main/java/com/android/volley/RequestQueue.java
+++ /dev/null
@@ -1,342 +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;
-
-import android.os.Handler;
-import android.os.Looper;
-import androidx.annotation.IntDef;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.PriorityBlockingQueue;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * A request dispatch queue with a thread pool of dispatchers.
- *
- * <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
- @Deprecated // Use RequestEventListener instead.
- public interface RequestFinishedListener<T> {
- /** Called when a request has finished processing. */
- void onRequestFinished(Request<T> request);
- }
-
- /** Request event types the listeners {@link RequestEventListener} will be notified about. */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- RequestEvent.REQUEST_QUEUED,
- RequestEvent.REQUEST_CACHE_LOOKUP_STARTED,
- RequestEvent.REQUEST_CACHE_LOOKUP_FINISHED,
- RequestEvent.REQUEST_NETWORK_DISPATCH_STARTED,
- RequestEvent.REQUEST_NETWORK_DISPATCH_FINISHED,
- RequestEvent.REQUEST_FINISHED
- })
- public @interface RequestEvent {
- /** The request was added to the queue. */
- public static final int REQUEST_QUEUED = 0;
- /** Cache lookup started for the request. */
- public static final int REQUEST_CACHE_LOOKUP_STARTED = 1;
- /**
- * Cache lookup finished for the request and cached response is delivered or request is
- * queued for network dispatching.
- */
- public static final int REQUEST_CACHE_LOOKUP_FINISHED = 2;
- /** Network dispatch started for the request. */
- public static final int REQUEST_NETWORK_DISPATCH_STARTED = 3;
- /** The network dispatch finished for the request and response (if any) is delivered. */
- public static final int REQUEST_NETWORK_DISPATCH_FINISHED = 4;
- /**
- * All the work associated with the request is finished and request is removed from all the
- * queues.
- */
- public static final int REQUEST_FINISHED = 5;
- }
-
- /** Callback interface for request life cycle events. */
- public interface RequestEventListener {
- /**
- * Called on every request lifecycle event. Can be called from different threads. The call
- * is blocking request processing, so any processing should be kept at minimum or moved to
- * another thread.
- */
- void onRequestEvent(Request<?> request, @RequestEvent int event);
- }
-
- /** Used for generating monotonically-increasing sequence numbers for requests. */
- 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.
- */
- private final Set<Request<?>> mCurrentRequests = new HashSet<>();
-
- /** The cache triage queue. */
- 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<>();
-
- /** Number of network request dispatcher threads to start. */
- private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
-
- /** Cache interface for retrieving and storing responses. */
- private final Cache mCache;
-
- /** Network interface for performing requests. */
- private final Network mNetwork;
-
- /** Response delivery mechanism. */
- private final ResponseDelivery mDelivery;
-
- /** The network dispatchers. */
- private final NetworkDispatcher[] mDispatchers;
-
- /** The cache dispatcher. */
- private CacheDispatcher mCacheDispatcher;
-
- private final List<RequestFinishedListener> mFinishedListeners = new ArrayList<>();
-
- /** Collection of listeners for request life cycle events. */
- private final List<RequestEventListener> mEventListeners = new ArrayList<>();
-
- /**
- * Creates the worker pool. Processing will not begin until {@link #start()} is called.
- *
- * @param cache A Cache to use for persisting responses to disk
- * @param network A Network interface for performing HTTP requests
- * @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) {
- mCache = cache;
- mNetwork = network;
- mDispatchers = new NetworkDispatcher[threadPoolSize];
- mDelivery = delivery;
- }
-
- /**
- * Creates the worker pool. Processing will not begin until {@link #start()} is called.
- *
- * @param cache A Cache to use for persisting responses to disk
- * @param network A Network interface for performing HTTP requests
- * @param threadPoolSize Number of network dispatcher threads to create
- */
- public RequestQueue(Cache cache, Network network, int threadPoolSize) {
- this(
- cache,
- network,
- threadPoolSize,
- new ExecutorDelivery(new Handler(Looper.getMainLooper())));
- }
-
- /**
- * Creates the worker pool. Processing will not begin until {@link #start()} is called.
- *
- * @param cache A Cache to use for persisting responses to disk
- * @param network A Network interface for performing HTTP requests
- */
- public RequestQueue(Cache cache, Network network) {
- this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
- }
-
- /** Starts the dispatchers in this queue. */
- public void start() {
- 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);
- mDispatchers[i] = networkDispatcher;
- networkDispatcher.start();
- }
- }
-
- /** Stops the cache and network dispatchers. */
- public void stop() {
- if (mCacheDispatcher != null) {
- mCacheDispatcher.quit();
- }
- for (final NetworkDispatcher mDispatcher : mDispatchers) {
- if (mDispatcher != null) {
- mDispatcher.quit();
- }
- }
- }
-
- /** Gets a sequence number. */
- public int getSequenceNumber() {
- return mSequenceGenerator.incrementAndGet();
- }
-
- /** 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)}.
- */
- public interface RequestFilter {
- boolean apply(Request<?> request);
- }
-
- /**
- * Cancels all requests in this queue for which the given filter applies.
- *
- * @param filter The filtering function to use
- */
- public void cancelAll(RequestFilter filter) {
- synchronized (mCurrentRequests) {
- for (Request<?> request : mCurrentRequests) {
- if (filter.apply(request)) {
- request.cancel();
- }
- }
- }
- }
-
- /**
- * 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;
- }
- });
- }
-
- /**
- * Adds a Request to the dispatch queue.
- *
- * @param request The request to service
- * @return The passed-in request
- */
- public <T> Request<T> add(Request<T> request) {
- // Tag the request as belonging to this queue and add it to the set of current requests.
- request.setRequestQueue(this);
- synchronized (mCurrentRequests) {
- mCurrentRequests.add(request);
- }
-
- // Process requests in the order they are added.
- request.setSequence(getSequenceNumber());
- request.addMarker("add-to-queue");
- sendRequestEvent(request, RequestEvent.REQUEST_QUEUED);
-
- beginRequest(request);
- return request;
- }
-
- <T> void beginRequest(Request<T> request) {
- // If the request is uncacheable, skip the cache queue and go straight to the network.
- if (!request.shouldCache()) {
- sendRequestOverNetwork(request);
- } else {
- mCacheQueue.add(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);
- }
- }
- sendRequestEvent(request, RequestEvent.REQUEST_FINISHED);
- }
-
- /** Sends a request life cycle event to the listeners. */
- void sendRequestEvent(Request<?> request, @RequestEvent int event) {
- synchronized (mEventListeners) {
- for (RequestEventListener listener : mEventListeners) {
- listener.onRequestEvent(request, event);
- }
- }
- }
-
- /** Add a listener for request life cycle events. */
- public void addRequestEventListener(RequestEventListener listener) {
- synchronized (mEventListeners) {
- mEventListeners.add(listener);
- }
- }
-
- /** Remove a listener for request life cycle events. */
- public void removeRequestEventListener(RequestEventListener listener) {
- synchronized (mEventListeners) {
- mEventListeners.remove(listener);
- }
- }
-
- @Deprecated // Use RequestEventListener instead.
- public <T> void addRequestFinishedListener(RequestFinishedListener<T> listener) {
- synchronized (mFinishedListeners) {
- mFinishedListeners.add(listener);
- }
- }
-
- /** Remove a RequestFinishedListener. Has no effect if listener was not previously added. */
- @Deprecated // Use RequestEventListener instead.
- public <T> void removeRequestFinishedListener(RequestFinishedListener<T> listener) {
- synchronized (mFinishedListeners) {
- mFinishedListeners.remove(listener);
- }
- }
-
- public ResponseDelivery getResponseDelivery() {
- return mDelivery;
- }
-
- <T> void sendRequestOverNetwork(Request<T> request) {
- mNetworkQueue.add(request);
- }
-}
diff --git a/src/main/java/com/android/volley/RequestTask.java b/src/main/java/com/android/volley/RequestTask.java
deleted file mode 100644
index 8eeaf2c..0000000
--- a/src/main/java/com/android/volley/RequestTask.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.android.volley;
-
-/** Abstract runnable that's a task to be completed by the RequestQueue. */
-public abstract class RequestTask<T> implements Runnable {
- final Request<T> mRequest;
-
- public RequestTask(Request<T> request) {
- mRequest = request;
- }
-
- @SuppressWarnings("unchecked")
- public int compareTo(RequestTask<?> other) {
- return mRequest.compareTo((Request<T>) other.mRequest);
- }
-}
diff --git a/src/main/java/com/android/volley/Response.java b/src/main/java/com/android/volley/Response.java
deleted file mode 100644
index 622bdc4..0000000
--- a/src/main/java/com/android/volley/Response.java
+++ /dev/null
@@ -1,84 +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;
-
-import androidx.annotation.Nullable;
-
-/**
- * Encapsulates a parsed response for delivery.
- *
- * @param <T> Parsed type of this response
- */
-public class Response<T> {
-
- /** Callback interface for delivering parsed responses. */
- public interface Listener<T> {
- /** Called when a response is received. */
- void onResponse(T response);
- }
-
- /** 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.
- */
- void onErrorResponse(VolleyError error);
- }
-
- /** Returns a successful response containing the parsed result. */
- public static <T> Response<T> success(@Nullable T result, @Nullable Cache.Entry cacheEntry) {
- return new Response<>(result, cacheEntry);
- }
-
- /**
- * 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<>(error);
- }
-
- /** Parsed response, can be null; always null in the case of error. */
- @Nullable public final T result;
-
- /** Cache metadata for this response; null if not cached or in the case of error. */
- @Nullable public final Cache.Entry cacheEntry;
-
- /** Detailed error information if <code>errorCode != OK</code>. */
- @Nullable public final VolleyError error;
-
- /** 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. */
- public boolean isSuccess() {
- return error == null;
- }
-
- private Response(@Nullable T result, @Nullable Cache.Entry cacheEntry) {
- this.result = result;
- this.cacheEntry = cacheEntry;
- this.error = null;
- }
-
- private Response(VolleyError error) {
- this.result = null;
- this.cacheEntry = null;
- this.error = error;
- }
-}
diff --git a/src/main/java/com/android/volley/ResponseDelivery.java b/src/main/java/com/android/volley/ResponseDelivery.java
deleted file mode 100644
index 10aa137..0000000
--- a/src/main/java/com/android/volley/ResponseDelivery.java
+++ /dev/null
@@ -1,31 +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;
-
-public interface ResponseDelivery {
- /** 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.
- */
- void postResponse(Request<?> request, Response<?> response, Runnable runnable);
-
- /** 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
deleted file mode 100644
index 3ef26de..0000000
--- a/src/main/java/com/android/volley/RetryPolicy.java
+++ /dev/null
@@ -1,56 +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;
-
-/**
- * Retry policy for a request.
- *
- * <p>A retry policy can control two parameters:
- *
- * <ul>
- * <li>The number of tries. This can be a simple counter or more complex logic based on the type
- * of error passed to {@link #retry(VolleyError)}, although {@link #getCurrentRetryCount()}
- * should always return the current retry count for logging purposes.
- * <li>The request timeout for each try, via {@link #getCurrentTimeout()}. In the common case that
- * a request times out before the response has been received from the server, retrying again
- * with a longer timeout can increase the likelihood of success (at the expense of causing the
- * user to wait longer, especially if the request still fails).
- * </ul>
- *
- * <p>Note that currently, retries triggered by a retry policy are attempted immediately in sequence
- * with no delay between them (although the time between tries may increase if the requests are
- * timing out and {@link #getCurrentTimeout()} is returning increasing values).
- *
- * <p>By default, Volley uses {@link DefaultRetryPolicy}.
- */
-public interface RetryPolicy {
-
- /** Returns the current timeout (used for logging). */
- int getCurrentTimeout();
-
- /** 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.
- */
- 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
deleted file mode 100644
index 84b2eb4..0000000
--- a/src/main/java/com/android/volley/ServerError.java
+++ /dev/null
@@ -1,29 +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;
-
-/** Indicates that the server responded with an error response. */
-@SuppressWarnings("serial")
-public class ServerError extends VolleyError {
- public ServerError(NetworkResponse networkResponse) {
- super(networkResponse);
- }
-
- public ServerError() {
- super();
- }
-}
diff --git a/src/main/java/com/android/volley/TimeoutError.java b/src/main/java/com/android/volley/TimeoutError.java
deleted file mode 100644
index 227ae08..0000000
--- a/src/main/java/com/android/volley/TimeoutError.java
+++ /dev/null
@@ -1,21 +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;
-
-/** Indicates that the connection or the socket timed out. */
-@SuppressWarnings("serial")
-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
deleted file mode 100644
index 45086da..0000000
--- a/src/main/java/com/android/volley/VolleyError.java
+++ /dev/null
@@ -1,55 +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;
-
-/** Exception style class encapsulating Volley errors */
-@SuppressWarnings("serial")
-public class VolleyError extends Exception {
- public final NetworkResponse networkResponse;
- private long networkTimeMs;
-
- public VolleyError() {
- networkResponse = null;
- }
-
- public VolleyError(NetworkResponse response) {
- networkResponse = response;
- }
-
- public VolleyError(String exceptionMessage) {
- super(exceptionMessage);
- networkResponse = null;
- }
-
- public VolleyError(String exceptionMessage, Throwable reason) {
- super(exceptionMessage, reason);
- networkResponse = null;
- }
-
- public VolleyError(Throwable cause) {
- super(cause);
- networkResponse = null;
- }
-
- /* package */ void setNetworkTimeMs(long networkTimeMs) {
- this.networkTimeMs = networkTimeMs;
- }
-
- public long getNetworkTimeMs() {
- return networkTimeMs;
- }
-}
diff --git a/src/main/java/com/android/volley/VolleyLog.java b/src/main/java/com/android/volley/VolleyLog.java
deleted file mode 100644
index 8477668..0000000
--- a/src/main/java/com/android/volley/VolleyLog.java
+++ /dev/null
@@ -1,182 +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;
-
-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>
- * {@code <android-sdk>/platform-tools/adb shell setprop log.tag.Volley VERBOSE}
- */
-public class VolleyLog {
- public static String TAG = "Volley";
-
- public static boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
-
- /**
- * {@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.&lt;tag&gt;}
- */
- public static void setTag(String tag) {
- d("Changing log tag to %s", tag);
- TAG = tag;
-
- // Reinitialize the DEBUG "constant"
- DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
- }
-
- public static void v(String format, Object... args) {
- if (DEBUG) {
- Log.v(TAG, buildMessage(format, args));
- }
- }
-
- public static void d(String format, Object... args) {
- Log.d(TAG, buildMessage(format, args));
- }
-
- public static void e(String format, Object... args) {
- Log.e(TAG, buildMessage(format, args));
- }
-
- public static void e(Throwable tr, String format, Object... args) {
- Log.e(TAG, buildMessage(format, args), tr);
- }
-
- public static void wtf(String format, Object... args) {
- Log.wtf(TAG, buildMessage(format, args));
- }
-
- public static void wtf(Throwable tr, String format, Object... args) {
- Log.wtf(TAG, buildMessage(format, args), tr);
- }
-
- /**
- * 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);
- StackTraceElement[] trace = new Throwable().fillInStackTrace().getStackTrace();
-
- String caller = "<unknown>";
- // 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++) {
- 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);
-
- caller = callingClass + "." + trace[i].getMethodName();
- break;
- }
- }
- 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. */
- static class MarkerLog {
- public static final boolean ENABLED = VolleyLog.DEBUG;
-
- /** Minimum duration from first marker to last in an marker log to warrant logging. */
- private static final long MIN_DURATION_FOR_LOGGING_MS = 0;
-
- private static class Marker {
- public final String name;
- public final long thread;
- public final long time;
-
- public Marker(String name, long thread, long time) {
- this.name = name;
- this.thread = thread;
- this.time = time;
- }
- }
-
- private final List<Marker> mMarkers = new ArrayList<>();
- private boolean mFinished = false;
-
- /** Adds a marker to this log with the specified name. */
- public synchronized void add(String name, long threadId) {
- if (mFinished) {
- throw new IllegalStateException("Marker added to finished log");
- }
-
- mMarkers.add(new Marker(name, threadId, SystemClock.elapsedRealtime()));
- }
-
- /**
- * 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) {
- mFinished = true;
-
- long duration = getTotalDuration();
- if (duration <= MIN_DURATION_FOR_LOGGING_MS) {
- return;
- }
-
- long prevTime = mMarkers.get(0).time;
- d("(%-4d ms) %s", duration, header);
- for (Marker marker : mMarkers) {
- long thisTime = marker.time;
- d("(+%-4d) [%2d] %s", (thisTime - prevTime), marker.thread, marker.name);
- prevTime = thisTime;
- }
- }
-
- @Override
- protected void finalize() throws Throwable {
- // Catch requests that have been collected (and hence end-of-lifed)
- // but had no debugging output printed for them.
- if (!mFinished) {
- finish("Request on the loose");
- e("Marker log finalized without finish() - uncaught exit point for request");
- }
- }
-
- /** Returns the time difference between the first and last events in this log. */
- private long getTotalDuration() {
- if (mMarkers.size() == 0) {
- return 0;
- }
-
- long first = mMarkers.get(0).time;
- long last = mMarkers.get(mMarkers.size() - 1).time;
- return last - first;
- }
- }
-}
diff --git a/src/main/java/com/android/volley/WaitingRequestManager.java b/src/main/java/com/android/volley/WaitingRequestManager.java
deleted file mode 100644
index 682e339..0000000
--- a/src/main/java/com/android/volley/WaitingRequestManager.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2020 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;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.BlockingQueue;
-
-/**
- * Callback to notify the caller when the network request returns. Valid responses can be used by
- * all duplicate requests.
- */
-class WaitingRequestManager implements Request.NetworkRequestCompleteListener {
-
- /**
- * 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>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<>();
-
- private final ResponseDelivery mResponseDelivery;
-
- /**
- * RequestQueue that is passed in by the AsyncRequestQueue. This is null when this instance is
- * initialized by the {@link CacheDispatcher}
- */
- @Nullable private final RequestQueue mRequestQueue;
-
- /**
- * CacheDispacter that is passed in by the CacheDispatcher. This is null when this instance is
- * initialized by the {@link AsyncRequestQueue}
- */
- @Nullable private final CacheDispatcher mCacheDispatcher;
-
- /**
- * BlockingQueue that is passed in by the CacheDispatcher. This is null when this instance is
- * initialized by the {@link AsyncRequestQueue}
- */
- @Nullable private final BlockingQueue<Request<?>> mNetworkQueue;
-
- WaitingRequestManager(@NonNull RequestQueue requestQueue) {
- mRequestQueue = requestQueue;
- mResponseDelivery = mRequestQueue.getResponseDelivery();
- mCacheDispatcher = null;
- mNetworkQueue = null;
- }
-
- WaitingRequestManager(
- @NonNull CacheDispatcher cacheDispatcher,
- @NonNull BlockingQueue<Request<?>> networkQueue,
- ResponseDelivery responseDelivery) {
- mRequestQueue = null;
- mResponseDelivery = responseDelivery;
- mCacheDispatcher = cacheDispatcher;
- mNetworkQueue = networkQueue;
- }
-
- /** Request received a valid response that can be used by other waiting requests. */
- @Override
- public void onResponseReceived(Request<?> request, Response<?> response) {
- if (response.cacheEntry == null || response.cacheEntry.isExpired()) {
- onNoUsableResponseReceived(request);
- return;
- }
- String cacheKey = request.getCacheKey();
- List<Request<?>> waitingRequests;
- synchronized (this) {
- waitingRequests = mWaitingRequests.remove(cacheKey);
- }
- if (waitingRequests != null) {
- if (VolleyLog.DEBUG) {
- VolleyLog.v(
- "Releasing %d waiting requests for cacheKey=%s.",
- waitingRequests.size(), cacheKey);
- }
- // Process all queued up requests.
- for (Request<?> waiting : waitingRequests) {
- mResponseDelivery.postResponse(waiting, response);
- }
- }
- }
-
- /** No valid response received from network, release waiting requests. */
- @Override
- public synchronized void onNoUsableResponseReceived(Request<?> request) {
- String cacheKey = request.getCacheKey();
- 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",
- waitingRequests.size(), cacheKey);
- }
- Request<?> nextInLine = waitingRequests.remove(0);
- mWaitingRequests.put(cacheKey, waitingRequests);
- nextInLine.setNetworkRequestCompleteListener(this);
- // RequestQueue will be non-null if this instance was created in AsyncRequestQueue.
- if (mRequestQueue != null) {
- // Will send the network request from the RequestQueue.
- mRequestQueue.sendRequestOverNetwork(nextInLine);
- } else if (mCacheDispatcher != null && mNetworkQueue != null) {
- // If we're not using the AsyncRequestQueue, then submit it to the network queue.
- try {
- mNetworkQueue.put(nextInLine);
- } catch (InterruptedException iex) {
- VolleyLog.e("Couldn't add request to queue. %s", iex.toString());
- // Restore the interrupted status of the calling thread (i.e. NetworkDispatcher)
- Thread.currentThread().interrupt();
- // Quit the current CacheDispatcher thread.
- mCacheDispatcher.quit();
- }
- }
- }
- }
-
- /**
- * 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.
- */
- synchronized boolean maybeAddToWaitingRequests(Request<?> request) {
- String cacheKey = request.getCacheKey();
- // Insert request into stage if there's already a request with the same cache key
- // in flight.
- if (mWaitingRequests.containsKey(cacheKey)) {
- // There is already a request in flight. Queue up.
- List<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
- if (stagedRequests == null) {
- stagedRequests = new ArrayList<>();
- }
- request.addMarker("waiting-for-response");
- stagedRequests.add(request);
- mWaitingRequests.put(cacheKey, stagedRequests);
- if (VolleyLog.DEBUG) {
- VolleyLog.d("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
- }
- return true;
- } else {
- // Insert 'null' queue for this cacheKey, indicating there is now a request in
- // flight.
- mWaitingRequests.put(cacheKey, null);
- request.setNetworkRequestCompleteListener(this);
- if (VolleyLog.DEBUG) {
- VolleyLog.d("new request, sending to network %s", cacheKey);
- }
- return false;
- }
- }
-}
diff --git a/src/main/java/com/android/volley/cronet/CronetHttpStack.java b/src/main/java/com/android/volley/cronet/CronetHttpStack.java
deleted file mode 100644
index f3baace..0000000
--- a/src/main/java/com/android/volley/cronet/CronetHttpStack.java
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * Copyright (C) 2020 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.cronet;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Base64;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-import com.android.volley.AuthFailureError;
-import com.android.volley.Header;
-import com.android.volley.Request;
-import com.android.volley.RequestTask;
-import com.android.volley.VolleyLog;
-import com.android.volley.toolbox.AsyncHttpStack;
-import com.android.volley.toolbox.ByteArrayPool;
-import com.android.volley.toolbox.HttpHeaderParser;
-import com.android.volley.toolbox.HttpResponse;
-import com.android.volley.toolbox.PoolingByteArrayOutputStream;
-import com.android.volley.toolbox.UrlRewriter;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.WritableByteChannel;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import org.chromium.net.CronetEngine;
-import org.chromium.net.CronetException;
-import org.chromium.net.UploadDataProvider;
-import org.chromium.net.UploadDataProviders;
-import org.chromium.net.UrlRequest;
-import org.chromium.net.UrlRequest.Callback;
-import org.chromium.net.UrlResponseInfo;
-
-/**
- * A {@link AsyncHttpStack} that's based on Cronet's fully asynchronous API for network requests.
- */
-public class CronetHttpStack extends AsyncHttpStack {
-
- private final CronetEngine mCronetEngine;
- private final ByteArrayPool mPool;
- private final UrlRewriter mUrlRewriter;
- private final RequestListener mRequestListener;
-
- // cURL logging support
- private final boolean mCurlLoggingEnabled;
- private final CurlCommandLogger mCurlCommandLogger;
- private final boolean mLogAuthTokensInCurlCommands;
-
- private CronetHttpStack(
- CronetEngine cronetEngine,
- ByteArrayPool pool,
- UrlRewriter urlRewriter,
- RequestListener requestListener,
- boolean curlLoggingEnabled,
- CurlCommandLogger curlCommandLogger,
- boolean logAuthTokensInCurlCommands) {
- mCronetEngine = cronetEngine;
- mPool = pool;
- mUrlRewriter = urlRewriter;
- mRequestListener = requestListener;
- mCurlLoggingEnabled = curlLoggingEnabled;
- mCurlCommandLogger = curlCommandLogger;
- mLogAuthTokensInCurlCommands = logAuthTokensInCurlCommands;
-
- mRequestListener.initialize(this);
- }
-
- @Override
- public void executeRequest(
- final Request<?> request,
- final Map<String, String> additionalHeaders,
- final OnRequestComplete callback) {
- if (getBlockingExecutor() == null || getNonBlockingExecutor() == null) {
- throw new IllegalStateException("Must set blocking and non-blocking executors");
- }
- final Callback urlCallback =
- new Callback() {
- PoolingByteArrayOutputStream bytesReceived = null;
- WritableByteChannel receiveChannel = null;
-
- @Override
- public void onRedirectReceived(
- UrlRequest urlRequest,
- UrlResponseInfo urlResponseInfo,
- String newLocationUrl) {
- urlRequest.followRedirect();
- }
-
- @Override
- public void onResponseStarted(
- UrlRequest urlRequest, UrlResponseInfo urlResponseInfo) {
- bytesReceived =
- new PoolingByteArrayOutputStream(
- mPool, getContentLength(urlResponseInfo));
- receiveChannel = Channels.newChannel(bytesReceived);
- urlRequest.read(ByteBuffer.allocateDirect(1024));
- }
-
- @Override
- public void onReadCompleted(
- UrlRequest urlRequest,
- UrlResponseInfo urlResponseInfo,
- ByteBuffer byteBuffer) {
- byteBuffer.flip();
- try {
- receiveChannel.write(byteBuffer);
- byteBuffer.clear();
- urlRequest.read(byteBuffer);
- } catch (IOException e) {
- urlRequest.cancel();
- callback.onError(e);
- }
- }
-
- @Override
- public void onSucceeded(
- UrlRequest urlRequest, UrlResponseInfo urlResponseInfo) {
- List<Header> headers = getHeaders(urlResponseInfo.getAllHeadersAsList());
- HttpResponse response =
- new HttpResponse(
- urlResponseInfo.getHttpStatusCode(),
- headers,
- bytesReceived.toByteArray());
- callback.onSuccess(response);
- }
-
- @Override
- public void onFailed(
- UrlRequest urlRequest,
- UrlResponseInfo urlResponseInfo,
- CronetException e) {
- callback.onError(e);
- }
- };
-
- String url = request.getUrl();
- String rewritten = mUrlRewriter.rewriteUrl(url);
- if (rewritten == null) {
- callback.onError(new IOException("URL blocked by rewriter: " + url));
- return;
- }
- url = rewritten;
-
- // We can call allowDirectExecutor here and run directly on the network thread, since all
- // the callbacks are non-blocking.
- final UrlRequest.Builder builder =
- mCronetEngine
- .newUrlRequestBuilder(url, urlCallback, getNonBlockingExecutor())
- .allowDirectExecutor()
- .disableCache()
- .setPriority(getPriority(request));
- // request.getHeaders() may be blocking, so submit it to the blocking executor.
- getBlockingExecutor()
- .execute(
- new SetUpRequestTask<>(request, url, builder, additionalHeaders, callback));
- }
-
- private class SetUpRequestTask<T> extends RequestTask<T> {
- UrlRequest.Builder builder;
- String url;
- Map<String, String> additionalHeaders;
- OnRequestComplete callback;
- Request<T> request;
-
- SetUpRequestTask(
- Request<T> request,
- String url,
- UrlRequest.Builder builder,
- Map<String, String> additionalHeaders,
- OnRequestComplete callback) {
- super(request);
- // Note that this URL may be different from Request#getUrl() due to the UrlRewriter.
- this.url = url;
- this.builder = builder;
- this.additionalHeaders = additionalHeaders;
- this.callback = callback;
- this.request = request;
- }
-
- @Override
- public void run() {
- try {
- mRequestListener.onRequestPrepared(request, builder);
- CurlLoggedRequestParameters requestParameters = new CurlLoggedRequestParameters();
- setHttpMethod(requestParameters, request);
- setRequestHeaders(requestParameters, request, additionalHeaders);
- requestParameters.applyToRequest(builder, getNonBlockingExecutor());
- UrlRequest urlRequest = builder.build();
- if (mCurlLoggingEnabled) {
- mCurlCommandLogger.logCurlCommand(generateCurlCommand(url, requestParameters));
- }
- urlRequest.start();
- } catch (AuthFailureError authFailureError) {
- callback.onAuthError(authFailureError);
- }
- }
- }
-
- @VisibleForTesting
- public static List<Header> getHeaders(List<Map.Entry<String, String>> headersList) {
- List<Header> headers = new ArrayList<>();
- for (Map.Entry<String, String> header : headersList) {
- headers.add(new Header(header.getKey(), header.getValue()));
- }
- return headers;
- }
-
- /** Sets the connection parameters for the UrlRequest */
- private void setHttpMethod(CurlLoggedRequestParameters requestParameters, Request<?> request)
- throws AuthFailureError {
- switch (request.getMethod()) {
- case Request.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) {
- requestParameters.setHttpMethod("POST");
- addBodyIfExists(requestParameters, request.getPostBodyContentType(), postBody);
- } else {
- requestParameters.setHttpMethod("GET");
- }
- break;
- case Request.Method.GET:
- // Not necessary to set the request method because connection defaults to GET but
- // being explicit here.
- requestParameters.setHttpMethod("GET");
- break;
- case Request.Method.DELETE:
- requestParameters.setHttpMethod("DELETE");
- break;
- case Request.Method.POST:
- requestParameters.setHttpMethod("POST");
- addBodyIfExists(requestParameters, request.getBodyContentType(), request.getBody());
- break;
- case Request.Method.PUT:
- requestParameters.setHttpMethod("PUT");
- addBodyIfExists(requestParameters, request.getBodyContentType(), request.getBody());
- break;
- case Request.Method.HEAD:
- requestParameters.setHttpMethod("HEAD");
- break;
- case Request.Method.OPTIONS:
- requestParameters.setHttpMethod("OPTIONS");
- break;
- case Request.Method.TRACE:
- requestParameters.setHttpMethod("TRACE");
- break;
- case Request.Method.PATCH:
- requestParameters.setHttpMethod("PATCH");
- addBodyIfExists(requestParameters, request.getBodyContentType(), request.getBody());
- break;
- default:
- throw new IllegalStateException("Unknown method type.");
- }
- }
-
- /**
- * Sets the request headers for the UrlRequest.
- *
- * @param requestParameters parameters that we are adding the request headers to
- * @param request to get the headers from
- * @param additionalHeaders for the UrlRequest
- * @throws AuthFailureError is thrown if Request#getHeaders throws ones
- */
- private void setRequestHeaders(
- CurlLoggedRequestParameters requestParameters,
- Request<?> request,
- Map<String, String> additionalHeaders)
- throws AuthFailureError {
- requestParameters.putAllHeaders(additionalHeaders);
- // Request.getHeaders() takes precedence over the given additional (cache) headers).
- requestParameters.putAllHeaders(request.getHeaders());
- }
-
- /** Sets the UploadDataProvider of the UrlRequest.Builder */
- private void addBodyIfExists(
- CurlLoggedRequestParameters requestParameters,
- String contentType,
- @Nullable byte[] body) {
- requestParameters.setBody(contentType, body);
- }
-
- /** Helper method that maps Volley's request priority to Cronet's */
- private int getPriority(Request<?> request) {
- switch (request.getPriority()) {
- case LOW:
- return UrlRequest.Builder.REQUEST_PRIORITY_LOW;
- case HIGH:
- case IMMEDIATE:
- return UrlRequest.Builder.REQUEST_PRIORITY_HIGHEST;
- case NORMAL:
- default:
- return UrlRequest.Builder.REQUEST_PRIORITY_MEDIUM;
- }
- }
-
- private int getContentLength(UrlResponseInfo urlResponseInfo) {
- List<String> content = urlResponseInfo.getAllHeaders().get("Content-Length");
- if (content == null) {
- return 1024;
- } else {
- return Integer.parseInt(content.get(0));
- }
- }
-
- private String generateCurlCommand(String url, CurlLoggedRequestParameters requestParameters) {
- StringBuilder builder = new StringBuilder("curl ");
-
- // HTTP method
- builder.append("-X ").append(requestParameters.getHttpMethod()).append(" ");
-
- // Request headers
- for (Map.Entry<String, String> header : requestParameters.getHeaders().entrySet()) {
- builder.append("--header \"").append(header.getKey()).append(": ");
- if (!mLogAuthTokensInCurlCommands
- && ("Authorization".equals(header.getKey())
- || "Cookie".equals(header.getKey()))) {
- builder.append("[REDACTED]");
- } else {
- builder.append(header.getValue());
- }
- builder.append("\" ");
- }
-
- // URL
- builder.append("\"").append(url).append("\"");
-
- // Request body (if any)
- if (requestParameters.getBody() != null) {
- if (requestParameters.getBody().length >= 1024) {
- builder.append(" [REQUEST BODY TOO LARGE TO INCLUDE]");
- } else if (isBinaryContentForLogging(requestParameters)) {
- String base64 = Base64.encodeToString(requestParameters.getBody(), Base64.NO_WRAP);
- builder.insert(0, "echo '" + base64 + "' | base64 -d > /tmp/$$.bin; ")
- .append(" --data-binary @/tmp/$$.bin");
- } else {
- // Just assume the request body is UTF-8 since this is for debugging.
- try {
- builder.append(" --data-ascii \"")
- .append(new String(requestParameters.getBody(), "UTF-8"))
- .append("\"");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException("Could not encode to UTF-8", e);
- }
- }
- }
-
- return builder.toString();
- }
-
- /** Rough heuristic to determine whether the request body is binary, for logging purposes. */
- private boolean isBinaryContentForLogging(CurlLoggedRequestParameters requestParameters) {
- // Check to see if the content is gzip compressed - this means it should be treated as
- // binary content regardless of the content type.
- String contentEncoding = requestParameters.getHeaders().get("Content-Encoding");
- if (contentEncoding != null) {
- String[] encodings = TextUtils.split(contentEncoding, ",");
- for (String encoding : encodings) {
- if ("gzip".equals(encoding.trim())) {
- return true;
- }
- }
- }
-
- // If the content type is a known text type, treat it as text content.
- String contentType = requestParameters.getHeaders().get("Content-Type");
- if (contentType != null) {
- return !contentType.startsWith("text/")
- && !contentType.startsWith("application/xml")
- && !contentType.startsWith("application/json");
- }
-
- // Otherwise, assume it is binary content.
- return true;
- }
-
- /**
- * Builder is used to build an instance of {@link CronetHttpStack} from values configured by the
- * setters.
- */
- public static class Builder {
- private static final int DEFAULT_POOL_SIZE = 4096;
- private CronetEngine mCronetEngine;
- private final Context context;
- private ByteArrayPool mPool;
- private UrlRewriter mUrlRewriter;
- private RequestListener mRequestListener;
- private boolean mCurlLoggingEnabled;
- private CurlCommandLogger mCurlCommandLogger;
- private boolean mLogAuthTokensInCurlCommands;
-
- public Builder(Context context) {
- this.context = context;
- }
-
- /** Sets the CronetEngine to be used. Defaults to a vanialla CronetEngine. */
- public Builder setCronetEngine(CronetEngine engine) {
- mCronetEngine = engine;
- return this;
- }
-
- /** Sets the ByteArrayPool to be used. Defaults to a new pool with 4096 bytes. */
- public Builder setPool(ByteArrayPool pool) {
- mPool = pool;
- return this;
- }
-
- /** Sets the UrlRewriter to be used. Default is to return the original string. */
- public Builder setUrlRewriter(UrlRewriter urlRewriter) {
- mUrlRewriter = urlRewriter;
- return this;
- }
-
- /** Set the optional RequestListener to be used. */
- public Builder setRequestListener(RequestListener requestListener) {
- mRequestListener = requestListener;
- return this;
- }
-
- /**
- * Sets whether cURL logging should be enabled for debugging purposes.
- *
- * <p>When enabled, for each request dispatched to the network, a roughly-equivalent cURL
- * command will be logged to logcat.
- *
- * <p>The command may be missing some headers that are added by Cronet automatically, and
- * the full request body may not be included if it is too large. To inspect the full
- * requests and responses, see {@code CronetEngine#startNetLogToFile}.
- *
- * <p>WARNING: This is only intended for debugging purposes and should never be enabled on
- * production devices.
- *
- * @see #setCurlCommandLogger(CurlCommandLogger)
- * @see #setLogAuthTokensInCurlCommands(boolean)
- */
- public Builder setCurlLoggingEnabled(boolean curlLoggingEnabled) {
- mCurlLoggingEnabled = curlLoggingEnabled;
- return this;
- }
-
- /**
- * Sets the function used to log cURL commands.
- *
- * <p>Allows customization of the logging performed when cURL logging is enabled.
- *
- * <p>By default, when cURL logging is enabled, cURL commands are logged using {@link
- * VolleyLog#v}, e.g. at the verbose log level with the same log tag used by the rest of
- * Volley. This function may optionally be invoked to provide a custom logger.
- *
- * @see #setCurlLoggingEnabled(boolean)
- */
- public Builder setCurlCommandLogger(CurlCommandLogger curlCommandLogger) {
- mCurlCommandLogger = curlCommandLogger;
- return this;
- }
-
- /**
- * Sets whether to log known auth tokens in cURL commands, or redact them.
- *
- * <p>By default, headers which may contain auth tokens (e.g. Authorization or Cookie) will
- * have their values redacted. Passing true to this method will disable this redaction and
- * log the values of these headers.
- *
- * <p>This heuristic is not perfect; tokens that are logged in unknown headers, or in the
- * request body itself, will not be redacted as they cannot be detected generically.
- *
- * @see #setCurlLoggingEnabled(boolean)
- */
- public Builder setLogAuthTokensInCurlCommands(boolean logAuthTokensInCurlCommands) {
- mLogAuthTokensInCurlCommands = logAuthTokensInCurlCommands;
- return this;
- }
-
- public CronetHttpStack build() {
- if (mCronetEngine == null) {
- mCronetEngine = new CronetEngine.Builder(context).build();
- }
- if (mUrlRewriter == null) {
- mUrlRewriter =
- new UrlRewriter() {
- @Override
- public String rewriteUrl(String originalUrl) {
- return originalUrl;
- }
- };
- }
- if (mRequestListener == null) {
- mRequestListener = new RequestListener() {};
- }
- if (mPool == null) {
- mPool = new ByteArrayPool(DEFAULT_POOL_SIZE);
- }
- if (mCurlCommandLogger == null) {
- mCurlCommandLogger =
- new CurlCommandLogger() {
- @Override
- public void logCurlCommand(String curlCommand) {
- VolleyLog.v(curlCommand);
- }
- };
- }
- return new CronetHttpStack(
- mCronetEngine,
- mPool,
- mUrlRewriter,
- mRequestListener,
- mCurlLoggingEnabled,
- mCurlCommandLogger,
- mLogAuthTokensInCurlCommands);
- }
- }
-
- /** Callback interface allowing clients to intercept different parts of the request flow. */
- public abstract static class RequestListener {
- private CronetHttpStack mStack;
-
- void initialize(CronetHttpStack stack) {
- mStack = stack;
- }
-
- /**
- * Called when a request is prepared and about to be sent over the network.
- *
- * <p>Clients may use this callback to customize UrlRequests before they are dispatched,
- * e.g. to enable socket tagging or request finished listeners.
- */
- public void onRequestPrepared(Request<?> request, UrlRequest.Builder requestBuilder) {}
-
- /** @see AsyncHttpStack#getNonBlockingExecutor() */
- protected Executor getNonBlockingExecutor() {
- return mStack.getNonBlockingExecutor();
- }
-
- /** @see AsyncHttpStack#getBlockingExecutor() */
- protected Executor getBlockingExecutor() {
- return mStack.getBlockingExecutor();
- }
- }
-
- /**
- * Interface for logging cURL commands for requests.
- *
- * @see Builder#setCurlCommandLogger(CurlCommandLogger)
- */
- public interface CurlCommandLogger {
- /** Log the given cURL command. */
- void logCurlCommand(String curlCommand);
- }
-
- /**
- * Internal container class for request parameters that impact logged cURL commands.
- *
- * <p>When cURL logging is enabled, an equivalent cURL command to a given request must be
- * generated and logged. However, the Cronet UrlRequest object is write-only. So, we write any
- * relevant parameters into this read-write container so they can be referenced when generating
- * the cURL command (if needed) and then merged into the UrlRequest.
- */
- private static class CurlLoggedRequestParameters {
- private final TreeMap<String, String> mHeaders =
- new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- private String mHttpMethod;
- @Nullable private byte[] mBody;
-
- /**
- * Return the headers to be used for the request.
- *
- * <p>The returned map is case-insensitive.
- */
- TreeMap<String, String> getHeaders() {
- return mHeaders;
- }
-
- /** Apply all the headers in the given map to the request. */
- void putAllHeaders(Map<String, String> headers) {
- mHeaders.putAll(headers);
- }
-
- String getHttpMethod() {
- return mHttpMethod;
- }
-
- void setHttpMethod(String httpMethod) {
- mHttpMethod = httpMethod;
- }
-
- @Nullable
- byte[] getBody() {
- return mBody;
- }
-
- void setBody(String contentType, @Nullable byte[] body) {
- mBody = body;
- if (body != null && !mHeaders.containsKey(HttpHeaderParser.HEADER_CONTENT_TYPE)) {
- // Set the content-type unless it was already set (by Request#getHeaders).
- mHeaders.put(HttpHeaderParser.HEADER_CONTENT_TYPE, contentType);
- }
- }
-
- void applyToRequest(UrlRequest.Builder builder, ExecutorService nonBlockingExecutor) {
- for (Map.Entry<String, String> header : mHeaders.entrySet()) {
- builder.addHeader(header.getKey(), header.getValue());
- }
- builder.setHttpMethod(mHttpMethod);
- if (mBody != null) {
- UploadDataProvider dataProvider = UploadDataProviders.create(mBody);
- builder.setUploadDataProvider(dataProvider, nonBlockingExecutor);
- }
- }
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/AdaptedHttpStack.java b/src/main/java/com/android/volley/toolbox/AdaptedHttpStack.java
deleted file mode 100644
index c75c25f..0000000
--- a/src/main/java/com/android/volley/toolbox/AdaptedHttpStack.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2017 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.toolbox;
-
-import com.android.volley.AuthFailureError;
-import com.android.volley.Header;
-import com.android.volley.Request;
-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}.
- *
- * <p>{@link BasicNetwork} uses this if it is provided a {@link HttpStack} at construction time,
- * allowing it to have one implementation based atop {@link BaseHttpStack}.
- */
-@SuppressWarnings("deprecation")
-class AdaptedHttpStack extends BaseHttpStack {
-
- private final HttpStack mHttpStack;
-
- AdaptedHttpStack(HttpStack httpStack) {
- mHttpStack = httpStack;
- }
-
- @Override
- public HttpResponse executeRequest(Request<?> request, Map<String, String> additionalHeaders)
- throws IOException, AuthFailureError {
- org.apache.http.HttpResponse apacheResp;
- try {
- 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.
- throw new SocketTimeoutException(e.getMessage());
- }
-
- int statusCode = apacheResp.getStatusLine().getStatusCode();
-
- org.apache.http.Header[] headers = apacheResp.getAllHeaders();
- List<Header> headerList = new ArrayList<>(headers.length);
- for (org.apache.http.Header header : headers) {
- headerList.add(new Header(header.getName(), header.getValue()));
- }
-
- if (apacheResp.getEntity() == null) {
- return new HttpResponse(statusCode, headerList);
- }
-
- long contentLength = apacheResp.getEntity().getContentLength();
- if ((int) contentLength != contentLength) {
- throw new IOException("Response too large: " + contentLength);
- }
-
- return new HttpResponse(
- statusCode,
- headerList,
- (int) apacheResp.getEntity().getContentLength(),
- apacheResp.getEntity().getContent());
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java b/src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java
deleted file mode 100644
index f3381ae..0000000
--- a/src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java
+++ /dev/null
@@ -1,123 +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.toolbox;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerFuture;
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import androidx.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.
- */
-// TODO: Update this to account for runtime permissions
-@SuppressLint("MissingPermission")
-public class AndroidAuthenticator implements Authenticator {
- private final AccountManager mAccountManager;
- private final Account mAccount;
- private final String mAuthTokenType;
- private final boolean mNotifyAuthFailure;
-
- /**
- * 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, /* 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) {
- this(AccountManager.get(context), account, authTokenType, 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. */
- public Account getAccount() {
- return mAccount;
- }
-
- /** Returns the Auth Token Type used by this authenticator. */
- public String getAuthTokenType() {
- return mAuthTokenType;
- }
-
- // TODO: Figure out what to do about notifyAuthFailure
- @SuppressWarnings("deprecation")
- @Override
- public String getAuthToken() throws AuthFailureError {
- AccountManagerFuture<Bundle> future =
- mAccountManager.getAuthToken(
- mAccount,
- mAuthTokenType,
- mNotifyAuthFailure,
- /* callback= */ null,
- /* handler= */ null);
- Bundle result;
- try {
- result = future.getResult();
- } catch (Exception e) {
- throw new AuthFailureError("Error while retrieving auth token", e);
- }
- String authToken = null;
- if (future.isDone() && !future.isCancelled()) {
- if (result.containsKey(AccountManager.KEY_INTENT)) {
- Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
- throw new AuthFailureError(intent);
- }
- authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
- }
- if (authToken == null) {
- throw new AuthFailureError("Got null auth token for type: " + mAuthTokenType);
- }
-
- return authToken;
- }
-
- @Override
- public void invalidateAuthToken(String authToken) {
- mAccountManager.invalidateAuthToken(mAccount.type, authToken);
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/AsyncHttpStack.java b/src/main/java/com/android/volley/toolbox/AsyncHttpStack.java
deleted file mode 100644
index bafab8c..0000000
--- a/src/main/java/com/android/volley/toolbox/AsyncHttpStack.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2020 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.toolbox;
-
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-import com.android.volley.AuthFailureError;
-import com.android.volley.Request;
-import com.android.volley.VolleyLog;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.util.Map;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.atomic.AtomicReference;
-
-/** Asynchronous extension of the {@link BaseHttpStack} class. */
-public abstract class AsyncHttpStack extends BaseHttpStack {
- private ExecutorService mBlockingExecutor;
- private ExecutorService mNonBlockingExecutor;
-
- public interface OnRequestComplete {
- /** Invoked when the stack successfully completes a request. */
- void onSuccess(HttpResponse httpResponse);
-
- /** Invoked when the stack throws an {@link AuthFailureError} during a request. */
- void onAuthError(AuthFailureError authFailureError);
-
- /** Invoked when the stack throws an {@link IOException} during a request. */
- void onError(IOException ioException);
- }
-
- /**
- * Makes an HTTP request with the given parameters, and calls the {@link OnRequestComplete}
- * callback, with either the {@link HttpResponse} or error that was thrown.
- *
- * @param request to perform
- * @param additionalHeaders to be sent together with {@link Request#getHeaders()}
- * @param callback to be called after retrieving the {@link HttpResponse} or throwing an error.
- */
- public abstract void executeRequest(
- Request<?> request, Map<String, String> additionalHeaders, OnRequestComplete callback);
-
- /**
- * This method sets the non blocking executor to be used by the stack for non-blocking tasks.
- * This method must be called before executing any requests.
- */
- @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
- public void setNonBlockingExecutor(ExecutorService executor) {
- mNonBlockingExecutor = executor;
- }
-
- /**
- * This method sets the blocking executor to be used by the stack for potentially blocking
- * tasks. This method must be called before executing any requests.
- */
- @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
- public void setBlockingExecutor(ExecutorService executor) {
- mBlockingExecutor = executor;
- }
-
- /** Gets blocking executor to perform any potentially blocking tasks. */
- protected ExecutorService getBlockingExecutor() {
- return mBlockingExecutor;
- }
-
- /** Gets non-blocking executor to perform any non-blocking tasks. */
- protected ExecutorService getNonBlockingExecutor() {
- return mNonBlockingExecutor;
- }
-
- /**
- * Performs an HTTP request with the given parameters.
- *
- * @param request the request to perform
- * @param additionalHeaders additional headers to be sent together with {@link
- * Request#getHeaders()}
- * @return the {@link HttpResponse}
- * @throws IOException if an I/O error occurs during the request
- * @throws AuthFailureError if an authentication failure occurs during the request
- */
- @Override
- public final HttpResponse executeRequest(
- Request<?> request, Map<String, String> additionalHeaders)
- throws IOException, AuthFailureError {
- final CountDownLatch latch = new CountDownLatch(1);
- final AtomicReference<Response> entry = new AtomicReference<>();
- executeRequest(
- request,
- additionalHeaders,
- new OnRequestComplete() {
- @Override
- public void onSuccess(HttpResponse httpResponse) {
- Response response =
- new Response(
- httpResponse,
- /* ioException= */ null,
- /* authFailureError= */ null);
- entry.set(response);
- latch.countDown();
- }
-
- @Override
- public void onAuthError(AuthFailureError authFailureError) {
- Response response =
- new Response(
- /* httpResponse= */ null,
- /* ioException= */ null,
- authFailureError);
- entry.set(response);
- latch.countDown();
- }
-
- @Override
- public void onError(IOException ioException) {
- Response response =
- new Response(
- /* httpResponse= */ null,
- ioException,
- /* authFailureError= */ null);
- entry.set(response);
- latch.countDown();
- }
- });
- try {
- latch.await();
- } catch (InterruptedException e) {
- VolleyLog.e(e, "while waiting for CountDownLatch");
- Thread.currentThread().interrupt();
- throw new InterruptedIOException(e.toString());
- }
- Response response = entry.get();
- if (response.httpResponse != null) {
- return response.httpResponse;
- } else if (response.ioException != null) {
- throw response.ioException;
- } else {
- throw response.authFailureError;
- }
- }
-
- private static class Response {
- HttpResponse httpResponse;
- IOException ioException;
- AuthFailureError authFailureError;
-
- private Response(
- @Nullable HttpResponse httpResponse,
- @Nullable IOException ioException,
- @Nullable AuthFailureError authFailureError) {
- this.httpResponse = httpResponse;
- this.ioException = ioException;
- this.authFailureError = authFailureError;
- }
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/Authenticator.java b/src/main/java/com/android/volley/toolbox/Authenticator.java
deleted file mode 100644
index 2ba43db..0000000
--- a/src/main/java/com/android/volley/toolbox/Authenticator.java
+++ /dev/null
@@ -1,32 +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.toolbox;
-
-import com.android.volley.AuthFailureError;
-
-/** An interface for interacting with auth tokens. */
-public interface Authenticator {
- /**
- * Synchronously retrieves an auth token.
- *
- * @throws AuthFailureError If authentication did not succeed
- */
- String getAuthToken() throws AuthFailureError;
-
- /** 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
deleted file mode 100644
index 99a9899..0000000
--- a/src/main/java/com/android/volley/toolbox/BaseHttpStack.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 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.toolbox;
-
-import com.android.volley.AuthFailureError;
-import com.android.volley.Header;
-import com.android.volley.Request;
-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
-public abstract class BaseHttpStack implements 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().
- *
- * @param request the request to perform
- * @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
- * @throws AuthFailureError if an authentication failure occurs during the request
- */
- public abstract HttpResponse executeRequest(
- Request<?> request, Map<String, String> additionalHeaders)
- throws IOException, AuthFailureError;
-
- /**
- * @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.
- */
- @Deprecated
- @Override
- public final org.apache.http.HttpResponse performRequest(
- Request<?> request, Map<String, String> additionalHeaders)
- throws IOException, AuthFailureError {
- HttpResponse response = executeRequest(request, additionalHeaders);
-
- ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
- StatusLine statusLine =
- new BasicStatusLine(
- protocolVersion, response.getStatusCode(), /* reasonPhrase= */ "");
- BasicHttpResponse apacheResponse = new BasicHttpResponse(statusLine);
-
- List<org.apache.http.Header> headers = new ArrayList<>();
- for (Header header : response.getHeaders()) {
- headers.add(new BasicHeader(header.getName(), header.getValue()));
- }
- apacheResponse.setHeaders(headers.toArray(new org.apache.http.Header[0]));
-
- InputStream responseStream = response.getContent();
- if (responseStream != null) {
- BasicHttpEntity entity = new BasicHttpEntity();
- entity.setContent(responseStream);
- entity.setContentLength(response.getContentLength());
- apacheResponse.setEntity(entity);
- }
-
- return apacheResponse;
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/BasicAsyncNetwork.java b/src/main/java/com/android/volley/toolbox/BasicAsyncNetwork.java
deleted file mode 100644
index 55892a0..0000000
--- a/src/main/java/com/android/volley/toolbox/BasicAsyncNetwork.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2020 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.toolbox;
-
-import static com.android.volley.toolbox.NetworkUtility.logSlowRequests;
-
-import android.os.SystemClock;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-import com.android.volley.AsyncNetwork;
-import com.android.volley.AuthFailureError;
-import com.android.volley.Header;
-import com.android.volley.NetworkResponse;
-import com.android.volley.Request;
-import com.android.volley.RequestTask;
-import com.android.volley.VolleyError;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-
-/** A network performing Volley requests over an {@link HttpStack}. */
-public class BasicAsyncNetwork extends AsyncNetwork {
-
- private final AsyncHttpStack mAsyncStack;
- private final ByteArrayPool mPool;
-
- /**
- * @param httpStack HTTP stack to be used
- * @param pool a buffer pool that improves GC performance in copy operations
- */
- private BasicAsyncNetwork(AsyncHttpStack httpStack, ByteArrayPool pool) {
- mAsyncStack = httpStack;
- mPool = pool;
- }
-
- @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
- @Override
- public void setBlockingExecutor(ExecutorService executor) {
- super.setBlockingExecutor(executor);
- mAsyncStack.setBlockingExecutor(executor);
- }
-
- @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
- @Override
- public void setNonBlockingExecutor(ExecutorService executor) {
- super.setNonBlockingExecutor(executor);
- mAsyncStack.setNonBlockingExecutor(executor);
- }
-
- /* Method to be called after a successful network request */
- private void onRequestSucceeded(
- final Request<?> request,
- final long requestStartMs,
- final HttpResponse httpResponse,
- final OnRequestComplete callback) {
- final int statusCode = httpResponse.getStatusCode();
- final List<Header> responseHeaders = httpResponse.getHeaders();
- // Handle cache validation.
- if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
- long requestDuration = SystemClock.elapsedRealtime() - requestStartMs;
- callback.onSuccess(
- NetworkUtility.getNotModifiedNetworkResponse(
- request, requestDuration, responseHeaders));
- return;
- }
-
- byte[] responseContents = httpResponse.getContentBytes();
- if (responseContents == null && httpResponse.getContent() == null) {
- // Add 0 byte response as a way of honestly representing a
- // no-content request.
- responseContents = new byte[0];
- }
-
- if (responseContents != null) {
- onResponseRead(
- requestStartMs,
- statusCode,
- httpResponse,
- request,
- callback,
- responseHeaders,
- responseContents);
- return;
- }
-
- // The underlying AsyncHttpStack does not support asynchronous reading of the response into
- // a byte array, so we need to submit a blocking task to copy the response from the
- // InputStream instead.
- final InputStream inputStream = httpResponse.getContent();
- getBlockingExecutor()
- .execute(
- new ResponseParsingTask<>(
- inputStream,
- httpResponse,
- request,
- callback,
- requestStartMs,
- responseHeaders,
- statusCode));
- }
-
- /* Method to be called after a failed network request */
- private void onRequestFailed(
- Request<?> request,
- OnRequestComplete callback,
- IOException exception,
- long requestStartMs,
- @Nullable HttpResponse httpResponse,
- @Nullable byte[] responseContents) {
- try {
- NetworkUtility.handleException(
- request, exception, requestStartMs, httpResponse, responseContents);
- } catch (VolleyError volleyError) {
- callback.onError(volleyError);
- return;
- }
- performRequest(request, callback);
- }
-
- @Override
- public void performRequest(final Request<?> request, final OnRequestComplete callback) {
- if (getBlockingExecutor() == null) {
- throw new IllegalStateException(
- "mBlockingExecuter must be set before making a request");
- }
- final long requestStartMs = SystemClock.elapsedRealtime();
- // Gather headers.
- final Map<String, String> additionalRequestHeaders =
- HttpHeaderParser.getCacheHeaders(request.getCacheEntry());
- mAsyncStack.executeRequest(
- request,
- additionalRequestHeaders,
- new AsyncHttpStack.OnRequestComplete() {
- @Override
- public void onSuccess(HttpResponse httpResponse) {
- onRequestSucceeded(request, requestStartMs, httpResponse, callback);
- }
-
- @Override
- public void onAuthError(AuthFailureError authFailureError) {
- callback.onError(authFailureError);
- }
-
- @Override
- public void onError(IOException ioException) {
- onRequestFailed(
- request,
- callback,
- ioException,
- requestStartMs,
- /* httpResponse= */ null,
- /* responseContents= */ null);
- }
- });
- }
-
- /* Helper method that determines what to do after byte[] is received */
- private void onResponseRead(
- long requestStartMs,
- int statusCode,
- HttpResponse httpResponse,
- Request<?> request,
- OnRequestComplete callback,
- List<Header> responseHeaders,
- byte[] responseContents) {
- // if the request is slow, log it.
- long requestLifetime = SystemClock.elapsedRealtime() - requestStartMs;
- logSlowRequests(requestLifetime, request, responseContents, statusCode);
-
- if (statusCode < 200 || statusCode > 299) {
- onRequestFailed(
- request,
- callback,
- new IOException(),
- requestStartMs,
- httpResponse,
- responseContents);
- return;
- }
-
- callback.onSuccess(
- new NetworkResponse(
- statusCode,
- responseContents,
- /* notModified= */ false,
- SystemClock.elapsedRealtime() - requestStartMs,
- responseHeaders));
- }
-
- private class ResponseParsingTask<T> extends RequestTask<T> {
- InputStream inputStream;
- HttpResponse httpResponse;
- Request<T> request;
- OnRequestComplete callback;
- long requestStartMs;
- List<Header> responseHeaders;
- int statusCode;
-
- ResponseParsingTask(
- InputStream inputStream,
- HttpResponse httpResponse,
- Request<T> request,
- OnRequestComplete callback,
- long requestStartMs,
- List<Header> responseHeaders,
- int statusCode) {
- super(request);
- this.inputStream = inputStream;
- this.httpResponse = httpResponse;
- this.request = request;
- this.callback = callback;
- this.requestStartMs = requestStartMs;
- this.responseHeaders = responseHeaders;
- this.statusCode = statusCode;
- }
-
- @Override
- public void run() {
- byte[] finalResponseContents;
- try {
- finalResponseContents =
- NetworkUtility.inputStreamToBytes(
- inputStream, httpResponse.getContentLength(), mPool);
- } catch (IOException e) {
- onRequestFailed(request, callback, e, requestStartMs, httpResponse, null);
- return;
- }
- onResponseRead(
- requestStartMs,
- statusCode,
- httpResponse,
- request,
- callback,
- responseHeaders,
- finalResponseContents);
- }
- }
-
- /**
- * Builder is used to build an instance of {@link BasicAsyncNetwork} from values configured by
- * the setters.
- */
- public static class Builder {
- private static final int DEFAULT_POOL_SIZE = 4096;
- @NonNull private AsyncHttpStack mAsyncStack;
- private ByteArrayPool mPool;
-
- public Builder(@NonNull AsyncHttpStack httpStack) {
- mAsyncStack = httpStack;
- mPool = null;
- }
-
- /**
- * Sets the ByteArrayPool to be used. If not set, it will default to a pool with the default
- * pool size.
- */
- public Builder setPool(ByteArrayPool pool) {
- mPool = pool;
- return this;
- }
-
- /** Builds the {@link com.android.volley.toolbox.BasicAsyncNetwork} */
- public BasicAsyncNetwork build() {
- if (mPool == null) {
- mPool = new ByteArrayPool(DEFAULT_POOL_SIZE);
- }
- return new BasicAsyncNetwork(mAsyncStack, mPool);
- }
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/BasicNetwork.java b/src/main/java/com/android/volley/toolbox/BasicNetwork.java
deleted file mode 100644
index 06427fe..0000000
--- a/src/main/java/com/android/volley/toolbox/BasicNetwork.java
+++ /dev/null
@@ -1,163 +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.toolbox;
-
-import android.os.SystemClock;
-import com.android.volley.Header;
-import com.android.volley.Network;
-import com.android.volley.NetworkResponse;
-import com.android.volley.Request;
-import com.android.volley.VolleyError;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-/** A network performing Volley requests over an {@link HttpStack}. */
-public class BasicNetwork implements Network {
- private static final int DEFAULT_POOL_SIZE = 4096;
-
- /**
- * @deprecated Should never have been exposed in the API. This field may be removed in a future
- * release of Volley.
- */
- @Deprecated protected final HttpStack mHttpStack;
-
- private final BaseHttpStack mBaseHttpStack;
-
- protected final ByteArrayPool mPool;
-
- /**
- * @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.
- */
- @Deprecated
- public BasicNetwork(HttpStack 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.
- this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
- }
-
- /**
- * @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.
- */
- @Deprecated
- public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {
- mHttpStack = httpStack;
- mBaseHttpStack = new AdaptedHttpStack(httpStack);
- mPool = pool;
- }
-
- /** @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.
- this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
- }
-
- /**
- * @param httpStack HTTP stack to be used
- * @param pool a buffer pool that improves GC performance in copy operations
- */
- public BasicNetwork(BaseHttpStack httpStack, ByteArrayPool pool) {
- mBaseHttpStack = httpStack;
- // Populate mHttpStack for backwards compatibility, since it is a protected field. However,
- // we won't use it directly here, so clients which don't access it directly won't need to
- // depend on Apache HTTP.
- mHttpStack = httpStack;
- mPool = pool;
- }
-
- @Override
- public NetworkResponse performRequest(Request<?> request) throws VolleyError {
- long requestStart = SystemClock.elapsedRealtime();
- while (true) {
- HttpResponse httpResponse = null;
- byte[] responseContents = null;
- List<Header> responseHeaders = Collections.emptyList();
- try {
- // Gather headers.
- Map<String, String> additionalRequestHeaders =
- HttpHeaderParser.getCacheHeaders(request.getCacheEntry());
- httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders);
- int statusCode = httpResponse.getStatusCode();
-
- responseHeaders = httpResponse.getHeaders();
- // Handle cache validation.
- if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
- long requestDuration = SystemClock.elapsedRealtime() - requestStart;
- return NetworkUtility.getNotModifiedNetworkResponse(
- request, requestDuration, responseHeaders);
- }
-
- // Some responses such as 204s do not have content. We must check.
- InputStream inputStream = httpResponse.getContent();
- if (inputStream != null) {
- responseContents =
- NetworkUtility.inputStreamToBytes(
- inputStream, httpResponse.getContentLength(), mPool);
- } else {
- // 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.
- long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
- NetworkUtility.logSlowRequests(
- requestLifetime, request, responseContents, statusCode);
-
- if (statusCode < 200 || statusCode > 299) {
- throw new IOException();
- }
- return new NetworkResponse(
- statusCode,
- responseContents,
- /* notModified= */ false,
- SystemClock.elapsedRealtime() - requestStart,
- responseHeaders);
- } catch (IOException e) {
- // This will either throw an exception, breaking us from the loop, or will loop
- // again and retry the request.
- NetworkUtility.handleException(
- request, e, requestStart, httpResponse, responseContents);
- }
- }
- }
-
- /**
- * Converts Headers[] to Map&lt;String, String&gt;.
- *
- * @deprecated Should never have been exposed in the API. This method may be removed in a future
- * release of Volley.
- */
- @Deprecated
- protected static Map<String, String> convertHeaders(Header[] headers) {
- Map<String, String> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- for (int i = 0; i < headers.length; i++) {
- result.put(headers[i].getName(), headers[i].getValue());
- }
- return result;
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/ByteArrayPool.java b/src/main/java/com/android/volley/toolbox/ByteArrayPool.java
deleted file mode 100644
index 0134fa2..0000000
--- a/src/main/java/com/android/volley/toolbox/ByteArrayPool.java
+++ /dev/null
@@ -1,130 +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.toolbox;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-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
- * 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
- * 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 ArrayList<>();
-
- private final List<byte[]> mBuffersBySize = new ArrayList<>(64);
-
- /** The total size of the buffers in the pool */
- private int mCurrentSize = 0;
-
- /**
- * The maximum aggregate size of the buffers in the pool. Old buffers are discarded to stay
- * under this limit.
- */
- 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;
- }
- };
-
- /** @param sizeLimit the maximum size of the pool, in bytes */
- public ByteArrayPool(int sizeLimit) {
- mSizeLimit = sizeLimit;
- }
-
- /**
- * Returns a buffer from the pool if one is available in the requested size, or allocates a new
- * 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.
- * @return a byte[] buffer is always returned.
- */
- public synchronized byte[] getBuf(int len) {
- for (int i = 0; i < mBuffersBySize.size(); i++) {
- byte[] buf = mBuffersBySize.get(i);
- if (buf.length >= len) {
- mCurrentSize -= buf.length;
- mBuffersBySize.remove(i);
- mBuffersByLastUse.remove(buf);
- return buf;
- }
- }
- return new byte[len];
- }
-
- /**
- * Returns a buffer to the pool, throwing away old buffers if the pool would exceed its allotted
- * size.
- *
- * @param buf the buffer to return to the pool.
- */
- public synchronized void returnBuf(byte[] buf) {
- if (buf == null || buf.length > mSizeLimit) {
- return;
- }
- mBuffersByLastUse.add(buf);
- int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR);
- if (pos < 0) {
- pos = -pos - 1;
- }
- mBuffersBySize.add(pos, buf);
- mCurrentSize += buf.length;
- trim();
- }
-
- /** Removes buffers from the pool until it is under its size limit. */
- private synchronized void trim() {
- while (mCurrentSize > mSizeLimit) {
- byte[] buf = mBuffersByLastUse.remove(0);
- mBuffersBySize.remove(buf);
- 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
deleted file mode 100644
index 856ef80..0000000
--- a/src/main/java/com/android/volley/toolbox/ClearCacheRequest.java
+++ /dev/null
@@ -1,66 +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.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;
-
-/** 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
- */
- public ClearCacheRequest(Cache cache, Runnable callback) {
- super(Method.GET, null, null);
- mCache = cache;
- mCallback = callback;
- }
-
- @Override
- public boolean isCanceled() {
- // This is a little bit of a hack, but hey, why not.
- mCache.clear();
- if (mCallback != null) {
- Handler handler = new Handler(Looper.getMainLooper());
- handler.postAtFrontOfQueue(mCallback);
- }
- return true;
- }
-
- @Override
- public Priority getPriority() {
- return Priority.IMMEDIATE;
- }
-
- @Override
- protected Response<Object> parseNetworkResponse(NetworkResponse response) {
- return null;
- }
-
- @Override
- 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
deleted file mode 100644
index d4310e0..0000000
--- a/src/main/java/com/android/volley/toolbox/DiskBasedCache.java
+++ /dev/null
@@ -1,677 +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.toolbox;
-
-import android.os.SystemClock;
-import android.text.TextUtils;
-import androidx.annotation.VisibleForTesting;
-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;
-import java.io.EOFException;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-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.
- *
- * <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<>(16, .75f, true);
-
- /** Total amount of space currently used by the cache in bytes. */
- private long mTotalSize = 0;
-
- /** The supplier for the root directory to use for the cache. */
- private final FileSupplier mRootDirectorySupplier;
-
- /** The maximum size of the cache in bytes. */
- private final int mMaxCacheSizeInBytes;
-
- /** Default maximum disk usage in bytes. */
- private static final int DEFAULT_DISK_USAGE_BYTES = 5 * 1024 * 1024;
-
- /** High water mark percentage for the cache */
- @VisibleForTesting static final float HYSTERESIS_FACTOR = 0.9f;
-
- /** Magic number for current version of cache file format. */
- private static final int CACHE_MAGIC = 0x20150306;
-
- /**
- * 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. Note that the cache may
- * briefly exceed this size on disk when writing a new entry that pushes it over the limit
- * until the ensuing pruning completes.
- */
- public DiskBasedCache(final File rootDirectory, int maxCacheSizeInBytes) {
- mRootDirectorySupplier =
- new FileSupplier() {
- @Override
- public File get() {
- return rootDirectory;
- }
- };
- mMaxCacheSizeInBytes = maxCacheSizeInBytes;
- }
-
- /**
- * Constructs an instance of the DiskBasedCache at the specified directory.
- *
- * @param rootDirectorySupplier The supplier for the root directory of the cache.
- * @param maxCacheSizeInBytes The maximum size of the cache in bytes. Note that the cache may
- * briefly exceed this size on disk when writing a new entry that pushes it over the limit
- * until the ensuing pruning completes.
- */
- public DiskBasedCache(FileSupplier rootDirectorySupplier, int maxCacheSizeInBytes) {
- mRootDirectorySupplier = rootDirectorySupplier;
- mMaxCacheSizeInBytes = maxCacheSizeInBytes;
- }
-
- /**
- * 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);
- }
-
- /**
- * Constructs an instance of the DiskBasedCache at the specified directory using the default
- * maximum cache size of 5MB.
- *
- * @param rootDirectorySupplier The supplier for the root directory of the cache.
- */
- public DiskBasedCache(FileSupplier rootDirectorySupplier) {
- this(rootDirectorySupplier, DEFAULT_DISK_USAGE_BYTES);
- }
-
- /** Clears the cache. Deletes all cached files from disk. */
- @Override
- public synchronized void clear() {
- File[] files = mRootDirectorySupplier.get().listFiles();
- if (files != null) {
- for (File file : files) {
- file.delete();
- }
- }
- mEntries.clear();
- mTotalSize = 0;
- VolleyLog.d("Cache cleared.");
- }
-
- /** 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);
- // if the entry does not exist, return.
- if (entry == null) {
- return null;
- }
- File file = getFileForKey(key);
- try {
- 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);
- // Remove key whose contents on disk have been replaced.
- removeEntry(key);
- return null;
- }
- byte[] data = streamToBytes(cis, cis.bytesRemaining());
- return entry.toCacheEntry(data);
- } finally {
- // Any IOException thrown here is handled by the below catch block by design.
- //noinspection ThrowFromFinallyBlock
- cis.close();
- }
- } catch (IOException e) {
- VolleyLog.d("%s: %s", file.getAbsolutePath(), e.toString());
- remove(key);
- return null;
- }
- }
-
- /**
- * 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() {
- File rootDirectory = mRootDirectorySupplier.get();
- if (!rootDirectory.exists()) {
- if (!rootDirectory.mkdirs()) {
- VolleyLog.e("Unable to create cache dir %s", rootDirectory.getAbsolutePath());
- }
- return;
- }
- File[] files = rootDirectory.listFiles();
- if (files == null) {
- return;
- }
- for (File file : files) {
- try {
- long entrySize = file.length();
- CountingInputStream cis =
- new CountingInputStream(
- new BufferedInputStream(createInputStream(file)), entrySize);
- try {
- CacheHeader entry = CacheHeader.readHeader(cis);
- entry.size = entrySize;
- putEntry(entry.key, entry);
- } finally {
- // Any IOException thrown here is handled by the below catch block by design.
- //noinspection ThrowFromFinallyBlock
- cis.close();
- }
- } catch (IOException e) {
- //noinspection ResultOfMethodCallIgnored
- file.delete();
- }
- }
- }
-
- /**
- * Invalidates an entry in the cache.
- *
- * @param key Cache key
- * @param fullExpire True to fully expire the entry, false to soft expire
- */
- @Override
- public synchronized void invalidate(String key, boolean fullExpire) {
- Entry entry = get(key);
- if (entry != null) {
- entry.softTtl = 0;
- if (fullExpire) {
- entry.ttl = 0;
- }
- put(key, entry);
- }
- }
-
- /** Puts the entry with the specified key into the cache. */
- @Override
- public synchronized void put(String key, Entry entry) {
- // If adding this entry would trigger a prune, but pruning would cause the new entry to be
- // deleted, then skip writing the entry in the first place, as this is just churn.
- // Note that we don't include the cache header overhead in this calculation for simplicity,
- // so putting entries which are just below the threshold may still cause this churn.
- if (mTotalSize + entry.data.length > mMaxCacheSizeInBytes
- && entry.data.length > mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) {
- return;
- }
- File file = getFileForKey(key);
- try {
- BufferedOutputStream fos = new BufferedOutputStream(createOutputStream(file));
- CacheHeader e = new CacheHeader(key, entry);
- boolean success = e.writeHeader(fos);
- if (!success) {
- fos.close();
- VolleyLog.d("Failed to write header for %s", file.getAbsolutePath());
- throw new IOException();
- }
- fos.write(entry.data);
- fos.close();
- e.size = file.length();
- putEntry(key, e);
- pruneIfNeeded();
- } catch (IOException e) {
- boolean deleted = file.delete();
- if (!deleted) {
- VolleyLog.d("Could not clean up file %s", file.getAbsolutePath());
- }
- initializeIfRootDirectoryDeleted();
- }
- }
-
- /** 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",
- 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.
- */
- private String getFilenameForKey(String key) {
- int firstHalfLength = key.length() / 2;
- String localFilename = String.valueOf(key.substring(0, firstHalfLength).hashCode());
- localFilename += String.valueOf(key.substring(firstHalfLength).hashCode());
- return localFilename;
- }
-
- /** Returns a file object for the given cache key. */
- public File getFileForKey(String key) {
- return new File(mRootDirectorySupplier.get(), getFilenameForKey(key));
- }
-
- /** Re-initialize the cache if the directory was deleted. */
- private void initializeIfRootDirectoryDeleted() {
- if (!mRootDirectorySupplier.get().exists()) {
- VolleyLog.d("Re-initializing cache after external clearing.");
- mEntries.clear();
- mTotalSize = 0;
- initialize();
- }
- }
-
- /** Represents a supplier for {@link File}s. */
- public interface FileSupplier {
- File get();
- }
-
- /** Prunes the cache to fit the maximum size. */
- private void pruneIfNeeded() {
- if (mTotalSize < mMaxCacheSizeInBytes) {
- return;
- }
- if (VolleyLog.DEBUG) {
- VolleyLog.v("Pruning old cache entries.");
- }
-
- long before = mTotalSize;
- int prunedFiles = 0;
- long startTime = SystemClock.elapsedRealtime();
-
- Iterator<Map.Entry<String, CacheHeader>> iterator = mEntries.entrySet().iterator();
- while (iterator.hasNext()) {
- Map.Entry<String, CacheHeader> entry = iterator.next();
- CacheHeader e = entry.getValue();
- boolean deleted = getFileForKey(e.key).delete();
- if (deleted) {
- mTotalSize -= e.size;
- } else {
- VolleyLog.d(
- "Could not delete cache entry for key=%s, filename=%s",
- e.key, getFilenameForKey(e.key));
- }
- iterator.remove();
- prunedFiles++;
-
- if (mTotalSize < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) {
- break;
- }
- }
-
- if (VolleyLog.DEBUG) {
- 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.
- */
- private void putEntry(String key, CacheHeader entry) {
- if (!mEntries.containsKey(key)) {
- mTotalSize += entry.size;
- } else {
- CacheHeader oldEntry = mEntries.get(key);
- mTotalSize += (entry.size - oldEntry.size);
- }
- mEntries.put(key, entry);
- }
-
- /** Removes the entry identified by 'key' from the cache. */
- private void removeEntry(String key) {
- CacheHeader removed = mEntries.remove(key);
- if (removed != null) {
- mTotalSize -= removed.size;
- }
- }
-
- /**
- * 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
- 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.
- if (length < 0 || length > maxLength || (int) length != length) {
- throw new IOException("streamToBytes length=" + length + ", maxLength=" + maxLength);
- }
- byte[] bytes = new byte[(int) length];
- new DataInputStream(cis).readFully(bytes);
- return bytes;
- }
-
- @VisibleForTesting
- InputStream createInputStream(File file) throws FileNotFoundException {
- return new FileInputStream(file);
- }
-
- @VisibleForTesting
- OutputStream createOutputStream(File file) throws FileNotFoundException {
- return new FileOutputStream(file);
- }
-
- /** Handles holding onto the cache headers for an entry. */
- @VisibleForTesting
- static class CacheHeader {
- /**
- * The size of the data identified by this CacheHeader on disk (both header and data).
- *
- * <p>Must be set by the caller after it has been calculated.
- *
- * <p>This is not serialized to disk.
- */
- long size;
-
- /** The key that identifies the cache entry. */
- final String key;
-
- /** ETag for cache coherence. */
- final String etag;
-
- /** Date of this response as reported by the server. */
- final long serverDate;
-
- /** The last modified date for the requested object. */
- final long lastModified;
-
- /** TTL for this record. */
- final long ttl;
-
- /** Soft TTL for this record. */
- final long softTtl;
-
- /** 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) {
- this.key = key;
- this.etag = "".equals(etag) ? null : etag;
- this.serverDate = serverDate;
- this.lastModified = lastModified;
- this.ttl = ttl;
- this.softTtl = softTtl;
- this.allResponseHeaders = allResponseHeaders;
- }
-
- /**
- * 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,
- getAllResponseHeaders(entry));
- }
-
- private static List<Header> getAllResponseHeaders(Entry entry) {
- // If the entry contains all the response headers, use that field directly.
- if (entry.allResponseHeaders != null) {
- return entry.allResponseHeaders;
- }
-
- // Legacy fallback - copy headers from the map.
- return HttpHeaderParser.toAllHeaderList(entry.responseHeaders);
- }
-
- /**
- * 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
- */
- static CacheHeader readHeader(CountingInputStream is) throws IOException {
- int magic = readInt(is);
- if (magic != CACHE_MAGIC) {
- // don't bother deleting, it'll get pruned eventually
- throw new IOException();
- }
- String key = readString(is);
- String etag = readString(is);
- long serverDate = readLong(is);
- long lastModified = readLong(is);
- long ttl = readLong(is);
- long softTtl = readLong(is);
- List<Header> allResponseHeaders = readHeaderList(is);
- return new CacheHeader(
- key, etag, serverDate, lastModified, ttl, softTtl, allResponseHeaders);
- }
-
- /** Creates a cache entry for the specified data. */
- Entry toCacheEntry(byte[] data) {
- Entry e = new Entry();
- e.data = data;
- e.etag = etag;
- e.serverDate = serverDate;
- e.lastModified = lastModified;
- e.ttl = ttl;
- e.softTtl = softTtl;
- e.responseHeaders = HttpHeaderParser.toHeaderMap(allResponseHeaders);
- e.allResponseHeaders = Collections.unmodifiableList(allResponseHeaders);
- return e;
- }
-
- /** Writes the contents of this CacheHeader to the specified OutputStream. */
- boolean writeHeader(OutputStream os) {
- try {
- writeInt(os, CACHE_MAGIC);
- writeString(os, key);
- writeString(os, etag == null ? "" : etag);
- writeLong(os, serverDate);
- writeLong(os, lastModified);
- writeLong(os, ttl);
- writeLong(os, softTtl);
- writeHeaderList(allResponseHeaders, os);
- os.flush();
- return true;
- } catch (IOException e) {
- VolleyLog.d("%s", e.toString());
- return false;
- }
- }
- }
-
- @VisibleForTesting
- static class CountingInputStream extends FilterInputStream {
- private final long length;
- private long bytesRead;
-
- CountingInputStream(InputStream in, long length) {
- super(in);
- this.length = length;
- }
-
- @Override
- public int read() throws IOException {
- int result = super.read();
- if (result != -1) {
- bytesRead++;
- }
- return result;
- }
-
- @Override
- public int read(byte[] buffer, int offset, int count) throws IOException {
- int result = super.read(buffer, offset, count);
- if (result != -1) {
- bytesRead += result;
- }
- return result;
- }
-
- @VisibleForTesting
- long bytesRead() {
- return bytesRead;
- }
-
- long bytesRemaining() {
- return length - bytesRead;
- }
- }
-
- /*
- * Homebrewed simple serialization system used for reading and writing cache
- * headers on disk. Once upon a time, this used the standard Java
- * Object{Input,Output}Stream, but the default implementation relies heavily
- * on reflection (even for standard types) and generates a ton of garbage.
- *
- * TODO: Replace by standard DataInput and DataOutput in next cache version.
- */
-
- /**
- * 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();
- if (b == -1) {
- throw new EOFException();
- }
- return b;
- }
-
- static void writeInt(OutputStream os, int n) throws IOException {
- os.write((n >> 0) & 0xff);
- os.write((n >> 8) & 0xff);
- os.write((n >> 16) & 0xff);
- os.write((n >> 24) & 0xff);
- }
-
- static int readInt(InputStream is) throws IOException {
- int n = 0;
- n |= (read(is) << 0);
- n |= (read(is) << 8);
- n |= (read(is) << 16);
- n |= (read(is) << 24);
- return n;
- }
-
- 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));
- }
-
- static long readLong(InputStream is) throws IOException {
- long n = 0;
- n |= ((read(is) & 0xFFL) << 0);
- n |= ((read(is) & 0xFFL) << 8);
- n |= ((read(is) & 0xFFL) << 16);
- n |= ((read(is) & 0xFFL) << 24);
- n |= ((read(is) & 0xFFL) << 32);
- n |= ((read(is) & 0xFFL) << 40);
- n |= ((read(is) & 0xFFL) << 48);
- n |= ((read(is) & 0xFFL) << 56);
- return n;
- }
-
- static void writeString(OutputStream os, String s) throws IOException {
- byte[] b = s.getBytes("UTF-8");
- writeLong(os, b.length);
- os.write(b, 0, b.length);
- }
-
- static String readString(CountingInputStream cis) throws IOException {
- long n = readLong(cis);
- byte[] b = streamToBytes(cis, n);
- return new String(b, "UTF-8");
- }
-
- static void writeHeaderList(List<Header> headers, OutputStream os) throws IOException {
- if (headers != null) {
- writeInt(os, headers.size());
- for (Header header : headers) {
- writeString(os, header.getName());
- writeString(os, header.getValue());
- }
- } else {
- writeInt(os, 0);
- }
- }
-
- static List<Header> readHeaderList(CountingInputStream cis) throws IOException {
- int size = readInt(cis);
- 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();
- result.add(new Header(name, value));
- }
- return result;
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/FileSupplier.java b/src/main/java/com/android/volley/toolbox/FileSupplier.java
deleted file mode 100644
index 70898a6..0000000
--- a/src/main/java/com/android/volley/toolbox/FileSupplier.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2020 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.toolbox;
-
-import java.io.File;
-
-/** Represents a supplier for {@link File}s. */
-public interface FileSupplier {
- File get();
-}
diff --git a/src/main/java/com/android/volley/toolbox/HttpClientStack.java b/src/main/java/com/android/volley/toolbox/HttpClientStack.java
deleted file mode 100644
index 1e9e4b0..0000000
--- a/src/main/java/com/android/volley/toolbox/HttpClientStack.java
+++ /dev/null
@@ -1,201 +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.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;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpDelete;
-import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpHead;
-import org.apache.http.client.methods.HttpOptions;
-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.apache.http.entity.ByteArrayEntity;
-import org.apache.http.message.BasicNameValuePair;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-
-/**
- * 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.
- */
-@Deprecated
-public class HttpClientStack implements HttpStack {
- protected final HttpClient mClient;
-
- private static final String HEADER_CONTENT_TYPE = "Content-Type";
-
- public HttpClientStack(HttpClient client) {
- mClient = client;
- }
-
- private static void setHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {
- for (String key : headers.keySet()) {
- httpRequest.setHeader(key, headers.get(key));
- }
- }
-
- @SuppressWarnings("unused")
- private static List<NameValuePair> getPostParameterPairs(Map<String, String> postParams) {
- List<NameValuePair> result = new ArrayList<>(postParams.size());
- for (String key : postParams.keySet()) {
- result.add(new BasicNameValuePair(key, postParams.get(key)));
- }
- return result;
- }
-
- @Override
- public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
- throws IOException, AuthFailureError {
- HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
- setHeaders(httpRequest, additionalHeaders);
- // Request.getHeaders() takes precedence over the given additional (cache) headers) and any
- // headers set by createHttpRequest (like the Content-Type header).
- setHeaders(httpRequest, request.getHeaders());
- onPrepareRequest(httpRequest);
- HttpParams httpParams = httpRequest.getParams();
- int timeoutMs = request.getTimeoutMs();
- // TODO: Reevaluate this connection timeout based on more wide-scale
- // data collection and possibly different for wifi vs. 3G.
- HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
- HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
- return mClient.execute(httpRequest);
- }
-
- /** Creates the appropriate subclass of HttpUriRequest for passed in request. */
- @SuppressWarnings("deprecation")
- /* 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.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.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;
- }
- default:
- throw new IllegalStateException("Unknown request method.");
- }
- }
-
- private static void setEntityIfNonEmptyBody(
- HttpEntityEnclosingRequestBase httpRequest, Request<?> request)
- throws AuthFailureError {
- byte[] body = request.getBody();
- if (body != null) {
- HttpEntity entity = new ByteArrayEntity(body);
- httpRequest.setEntity(entity);
- }
- }
-
- /**
- * Called before the request is executed using the underlying HttpClient.
- *
- * <p>Overwrite in subclasses to augment the request.
- */
- protected void onPrepareRequest(HttpUriRequest request) throws IOException {
- // Nothing.
- }
-
- /**
- * The HttpPatch class does not exist in the Android framework, so this has been defined here.
- */
- public static final class HttpPatch extends HttpEntityEnclosingRequestBase {
-
- public static final String METHOD_NAME = "PATCH";
-
- public HttpPatch() {
- super();
- }
-
- public HttpPatch(final URI uri) {
- super();
- setURI(uri);
- }
-
- /** @throws IllegalArgumentException if the uri is invalid. */
- public HttpPatch(final String uri) {
- super();
- setURI(URI.create(uri));
- }
-
- @Override
- 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
deleted file mode 100644
index 0b29e80..0000000
--- a/src/main/java/com/android/volley/toolbox/HttpHeaderParser.java
+++ /dev/null
@@ -1,301 +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.toolbox;
-
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.RestrictTo.Scope;
-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;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TimeZone;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-/** Utility methods for parsing HTTP headers. */
-public class HttpHeaderParser {
-
- @RestrictTo({Scope.LIBRARY_GROUP})
- public static final String HEADER_CONTENT_TYPE = "Content-Type";
-
- private static final String DEFAULT_CONTENT_CHARSET = "ISO-8859-1";
-
- private static final String RFC1123_PARSE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
-
- // Hardcode 'GMT' rather than using 'zzz' since some platforms append an extraneous +00:00.
- // See #287.
- private static final String RFC1123_OUTPUT_FORMAT = "EEE, dd MMM yyyy HH:mm:ss 'GMT'";
-
- /**
- * Extracts a {@link com.android.volley.Cache.Entry} from a {@link NetworkResponse}.
- *
- * @param response The network response to parse headers from
- * @return a cache entry for the given response, or null if the response is not cacheable.
- */
- @Nullable
- public static Cache.Entry parseCacheHeaders(NetworkResponse response) {
- long now = System.currentTimeMillis();
-
- Map<String, String> headers = response.headers;
- if (headers == null) {
- return null;
- }
-
- long serverDate = 0;
- long lastModified = 0;
- long serverExpires = 0;
- long softExpire = 0;
- long finalExpire = 0;
- long maxAge = 0;
- long staleWhileRevalidate = 0;
- boolean hasCacheControl = false;
- boolean mustRevalidate = false;
-
- String serverEtag = null;
- String headerValue;
-
- headerValue = headers.get("Date");
- if (headerValue != null) {
- serverDate = parseDateAsEpoch(headerValue);
- }
-
- headerValue = headers.get("Cache-Control");
- if (headerValue != null) {
- hasCacheControl = true;
- 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")) {
- return null;
- } else if (token.startsWith("max-age=")) {
- try {
- maxAge = Long.parseLong(token.substring(8));
- } catch (Exception e) {
- }
- } else if (token.startsWith("stale-while-revalidate=")) {
- try {
- staleWhileRevalidate = Long.parseLong(token.substring(23));
- } catch (Exception e) {
- }
- } else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {
- mustRevalidate = true;
- }
- }
- }
-
- headerValue = headers.get("Expires");
- if (headerValue != null) {
- serverExpires = parseDateAsEpoch(headerValue);
- }
-
- headerValue = headers.get("Last-Modified");
- if (headerValue != null) {
- lastModified = parseDateAsEpoch(headerValue);
- }
-
- serverEtag = headers.get("ETag");
-
- // Cache-Control takes precedence over an Expires header, even if both exist and Expires
- // is more restrictive.
- if (hasCacheControl) {
- softExpire = now + maxAge * 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);
- finalExpire = softExpire;
- }
-
- Cache.Entry entry = new Cache.Entry();
- entry.data = response.data;
- entry.etag = serverEtag;
- entry.softTtl = softExpire;
- entry.ttl = finalExpire;
- entry.serverDate = serverDate;
- entry.lastModified = lastModified;
- entry.responseHeaders = headers;
- entry.allResponseHeaders = response.allHeaders;
-
- return entry;
- }
-
- /** 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
- return newUsGmtFormatter(RFC1123_PARSE_FORMAT).parse(dateStr).getTime();
- } catch (ParseException e) {
- // Date in invalid format, fallback to 0
- // If the value is either "0" or "-1" we only log to verbose,
- // these values are pretty common and cause log spam.
- String message = "Unable to parse dateStr: %s, falling back to 0";
- if ("0".equals(dateStr) || "-1".equals(dateStr)) {
- VolleyLog.v(message, dateStr);
- } else {
- VolleyLog.e(e, message, dateStr);
- }
-
- return 0;
- }
- }
-
- /** Format an epoch date in RFC1123 format. */
- static String formatEpochAsRfc1123(long epoch) {
- return newUsGmtFormatter(RFC1123_OUTPUT_FORMAT).format(new Date(epoch));
- }
-
- private static SimpleDateFormat newUsGmtFormatter(String format) {
- SimpleDateFormat formatter = new SimpleDateFormat(format, Locale.US);
- formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
- return formatter;
- }
-
- /**
- * Retrieve a charset from headers
- *
- * @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.
- */
- public static String parseCharset(
- @Nullable Map<String, String> headers, String defaultCharset) {
- if (headers == null) {
- return defaultCharset;
- }
- String contentType = headers.get(HEADER_CONTENT_TYPE);
- if (contentType != null) {
- String[] params = contentType.split(";", 0);
- for (int i = 1; i < params.length; i++) {
- String[] pair = params[i].trim().split("=", 0);
- if (pair.length == 2) {
- if (pair[0].equals("charset")) {
- return pair[1];
- }
- }
- }
- }
-
- return defaultCharset;
- }
-
- /**
- * 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(@Nullable Map<String, String> headers) {
- return parseCharset(headers, DEFAULT_CONTENT_CHARSET);
- }
-
- // Note - these are copied from NetworkResponse to avoid making them public (as needed to access
- // them from the .toolbox package), which would mean they'd become part of the Volley API.
- // TODO: Consider obfuscating official releases so we can share utility methods between Volley
- // and Toolbox without making them public APIs.
-
- static Map<String, String> toHeaderMap(List<Header> allHeaders) {
- Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- // Later elements in the list take precedence.
- for (Header header : allHeaders) {
- headers.put(header.getName(), header.getValue());
- }
- return headers;
- }
-
- static List<Header> toAllHeaderList(Map<String, String> headers) {
- List<Header> allHeaders = new ArrayList<>(headers.size());
- for (Map.Entry<String, String> header : headers.entrySet()) {
- allHeaders.add(new Header(header.getKey(), header.getValue()));
- }
- return allHeaders;
- }
-
- /**
- * Combine cache headers with network response headers for an HTTP 304 response.
- *
- * <p>An HTTP 304 response does not have all header fields. We have to use the header fields
- * from the cache entry plus the new ones from the response. See also:
- * http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
- *
- * @param responseHeaders Headers from the network response.
- * @param entry The cached response.
- * @return The combined list of headers.
- */
- static List<Header> combineHeaders(List<Header> responseHeaders, Cache.Entry entry) {
- // First, create a case-insensitive set of header names from the network
- // response.
- Set<String> headerNamesFromNetworkResponse = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
- if (!responseHeaders.isEmpty()) {
- for (Header header : responseHeaders) {
- headerNamesFromNetworkResponse.add(header.getName());
- }
- }
-
- // Second, add headers from the cache entry to the network response as long as
- // they didn't appear in the network response, which should take precedence.
- List<Header> combinedHeaders = new ArrayList<>(responseHeaders);
- if (entry.allResponseHeaders != null) {
- if (!entry.allResponseHeaders.isEmpty()) {
- for (Header header : entry.allResponseHeaders) {
- if (!headerNamesFromNetworkResponse.contains(header.getName())) {
- combinedHeaders.add(header);
- }
- }
- }
- } else {
- // Legacy caches only have entry.responseHeaders.
- if (!entry.responseHeaders.isEmpty()) {
- for (Map.Entry<String, String> header : entry.responseHeaders.entrySet()) {
- if (!headerNamesFromNetworkResponse.contains(header.getKey())) {
- combinedHeaders.add(new Header(header.getKey(), header.getValue()));
- }
- }
- }
- }
- return combinedHeaders;
- }
-
- static Map<String, String> getCacheHeaders(Cache.Entry entry) {
- // If there's no cache entry, we're done.
- if (entry == null) {
- return Collections.emptyMap();
- }
-
- Map<String, String> headers = new HashMap<>();
-
- if (entry.etag != null) {
- headers.put("If-None-Match", entry.etag);
- }
-
- if (entry.lastModified > 0) {
- headers.put(
- "If-Modified-Since", HttpHeaderParser.formatEpochAsRfc1123(entry.lastModified));
- }
-
- return headers;
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/HttpResponse.java b/src/main/java/com/android/volley/toolbox/HttpResponse.java
deleted file mode 100644
index 595f926..0000000
--- a/src/main/java/com/android/volley/toolbox/HttpResponse.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2017 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.toolbox;
-
-import androidx.annotation.Nullable;
-import com.android.volley.Header;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.List;
-
-/** A response from an HTTP server. */
-public final class HttpResponse {
-
- private final int mStatusCode;
- private final List<Header> mHeaders;
- private final int mContentLength;
- @Nullable private final InputStream mContent;
- @Nullable private final byte[] mContentBytes;
-
- /**
- * Construct a new HttpResponse for an empty response body.
- *
- * @param statusCode the HTTP status code of the response
- * @param headers the response headers
- */
- public HttpResponse(int statusCode, List<Header> headers) {
- this(statusCode, headers, /* contentLength= */ -1, /* content= */ null);
- }
-
- /**
- * Construct a new HttpResponse.
- *
- * @param statusCode the HTTP status code of the response
- * @param headers the response headers
- * @param contentLength the length of the response content. Ignored if there is no content.
- * @param content an {@link InputStream} of the response content. May be null to indicate that
- * the response has no content.
- */
- public HttpResponse(
- int statusCode, List<Header> headers, int contentLength, InputStream content) {
- mStatusCode = statusCode;
- mHeaders = headers;
- mContentLength = contentLength;
- mContent = content;
- mContentBytes = null;
- }
-
- /**
- * Construct a new HttpResponse.
- *
- * @param statusCode the HTTP status code of the response
- * @param headers the response headers
- * @param contentBytes a byte[] of the response content. This is an optimization for HTTP stacks
- * that natively support returning a byte[].
- */
- public HttpResponse(int statusCode, List<Header> headers, byte[] contentBytes) {
- mStatusCode = statusCode;
- mHeaders = headers;
- mContentLength = contentBytes.length;
- mContentBytes = contentBytes;
- mContent = null;
- }
-
- /** Returns the HTTP status code of the response. */
- public final int getStatusCode() {
- return mStatusCode;
- }
-
- /** Returns the response headers. Must not be mutated directly. */
- public final List<Header> getHeaders() {
- return Collections.unmodifiableList(mHeaders);
- }
-
- /** Returns the length of the content. Only valid if {@link #getContent} is non-null. */
- public final int getContentLength() {
- return mContentLength;
- }
-
- /**
- * If a byte[] was already provided by an HTTP stack that natively supports returning one, this
- * method will return that byte[] as an optimization over copying the bytes from an input
- * stream. It may return null, even if the response has content, as long as mContent is
- * provided.
- */
- @Nullable
- public final byte[] getContentBytes() {
- return mContentBytes;
- }
-
- /**
- * Returns an {@link InputStream} of the response content. May be null to indicate that the
- * response has no content.
- */
- @Nullable
- public final InputStream getContent() {
- if (mContent != null) {
- return mContent;
- } else if (mContentBytes != null) {
- return new ByteArrayInputStream(mContentBytes);
- } else {
- return null;
- }
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/HttpStack.java b/src/main/java/com/android/volley/toolbox/HttpStack.java
deleted file mode 100644
index 85179a7..0000000
--- a/src/main/java/com/android/volley/toolbox/HttpStack.java
+++ /dev/null
@@ -1,47 +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.toolbox;
-
-import com.android.volley.AuthFailureError;
-import com.android.volley.Request;
-import java.io.IOException;
-import java.util.Map;
-import org.apache.http.HttpResponse;
-
-/**
- * An HTTP stack abstraction.
- *
- * @deprecated This interface should be avoided as it depends on the deprecated Apache HTTP library.
- * Use {@link BaseHttpStack} to avoid this dependency. This class may be removed in a future
- * release of Volley.
- */
-@Deprecated
-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().
- *
- * @param request the request to perform
- * @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;
-}
diff --git a/src/main/java/com/android/volley/toolbox/HurlStack.java b/src/main/java/com/android/volley/toolbox/HurlStack.java
deleted file mode 100644
index 35c6a72..0000000
--- a/src/main/java/com/android/volley/toolbox/HurlStack.java
+++ /dev/null
@@ -1,321 +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.toolbox;
-
-import androidx.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.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-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;
-
-/** 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. */
- public interface UrlRewriter extends com.android.volley.toolbox.UrlRewriter {}
-
- private final UrlRewriter mUrlRewriter;
- private final SSLSocketFactory mSslSocketFactory;
-
- public HurlStack() {
- this(/* urlRewriter = */ null);
- }
-
- /** @param urlRewriter Rewriter to use for request URLs */
- public HurlStack(UrlRewriter urlRewriter) {
- this(urlRewriter, /* sslSocketFactory = */ null);
- }
-
- /**
- * @param urlRewriter Rewriter to use for request URLs
- * @param sslSocketFactory SSL factory to use for HTTPS connections
- */
- public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
- mUrlRewriter = urlRewriter;
- mSslSocketFactory = sslSocketFactory;
- }
-
- @Override
- public HttpResponse executeRequest(Request<?> request, Map<String, String> additionalHeaders)
- throws IOException, AuthFailureError {
- String url = request.getUrl();
- HashMap<String, String> map = new HashMap<>();
- map.putAll(additionalHeaders);
- // Request.getHeaders() takes precedence over the given additional (cache) headers).
- map.putAll(request.getHeaders());
- if (mUrlRewriter != null) {
- String rewritten = mUrlRewriter.rewriteUrl(url);
- if (rewritten == null) {
- throw new IOException("URL blocked by rewriter: " + url);
- }
- url = rewritten;
- }
- URL parsedUrl = new URL(url);
- HttpURLConnection connection = openConnection(parsedUrl, request);
- boolean keepConnectionOpen = false;
- try {
- for (String headerName : map.keySet()) {
- connection.setRequestProperty(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()));
- }
-
- // 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(),
- createInputStream(request, connection));
- } finally {
- if (!keepConnectionOpen) {
- connection.disconnect();
- }
- }
- }
-
- @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()) {
- // HttpUrlConnection includes the status line as a header with a null key; omit it here
- // since it's not really a header and the rest of Volley assumes non-null keys.
- if (entry.getKey() != null) {
- for (String value : entry.getValue()) {
- headerList.add(new Header(entry.getKey(), value));
- }
- }
- }
- return headerList;
- }
-
- /**
- * 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
- * @return whether the response has a body
- */
- 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;
- }
-
- /**
- * 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();
- }
- }
-
- /**
- * Create and return an InputStream from which the response will be read.
- *
- * <p>May be overridden by subclasses to manipulate or monitor this input stream.
- *
- * @param request current request.
- * @param connection current connection of request.
- * @return an InputStream from which the response will be read.
- */
- protected InputStream createInputStream(Request<?> request, HttpURLConnection connection) {
- return new UrlConnectionInputStream(connection);
- }
-
- /**
- * Initializes an {@link InputStream} from the given {@link HttpURLConnection}.
- *
- * @param connection
- * @return an HttpEntity populated with data from <code>connection</code>.
- */
- private static InputStream inputStreamFromConnection(HttpURLConnection connection) {
- InputStream inputStream;
- try {
- inputStream = connection.getInputStream();
- } catch (IOException ioe) {
- inputStream = connection.getErrorStream();
- }
- return inputStream;
- }
-
- /** Create an {@link HttpURLConnection} for the specified {@code url}. */
- protected HttpURLConnection createConnection(URL url) throws IOException {
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-
- // Workaround for the M release HttpURLConnection not observing the
- // HttpURLConnection.setFollowRedirects() property.
- // https://code.google.com/p/android/issues/detail?id=194495
- connection.setInstanceFollowRedirects(HttpURLConnection.getFollowRedirects());
-
- return connection;
- }
-
- /**
- * Opens an {@link HttpURLConnection} with parameters.
- *
- * @param url
- * @return an open connection
- * @throws IOException
- */
- private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {
- HttpURLConnection connection = createConnection(url);
-
- int timeoutMs = request.getTimeoutMs();
- connection.setConnectTimeout(timeoutMs);
- connection.setReadTimeout(timeoutMs);
- connection.setUseCaches(false);
- connection.setDoInput(true);
-
- // use caller-provided custom SslSocketFactory, if any, for HTTPS
- if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {
- ((HttpsURLConnection) connection).setSSLSocketFactory(mSslSocketFactory);
- }
-
- return connection;
- }
-
- // NOTE: Any request headers added here (via setRequestProperty or addRequestProperty) should be
- // checked against the existing properties in the connection and not overridden if already set.
- @SuppressWarnings("deprecation")
- /* package */ 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.
- // 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) {
- connection.setRequestMethod("POST");
- addBody(connection, request, postBody);
- }
- break;
- case Method.GET:
- // Not necessary to set the request method because connection defaults to GET but
- // being explicit here.
- connection.setRequestMethod("GET");
- break;
- case Method.DELETE:
- connection.setRequestMethod("DELETE");
- break;
- case Method.POST:
- connection.setRequestMethod("POST");
- addBodyIfExists(connection, request);
- break;
- case Method.PUT:
- connection.setRequestMethod("PUT");
- addBodyIfExists(connection, request);
- break;
- case Method.HEAD:
- connection.setRequestMethod("HEAD");
- break;
- case Method.OPTIONS:
- connection.setRequestMethod("OPTIONS");
- break;
- case Method.TRACE:
- connection.setRequestMethod("TRACE");
- break;
- case Method.PATCH:
- connection.setRequestMethod("PATCH");
- addBodyIfExists(connection, request);
- break;
- default:
- throw new IllegalStateException("Unknown method type.");
- }
- }
-
- private void addBodyIfExists(HttpURLConnection connection, Request<?> request)
- throws IOException, AuthFailureError {
- byte[] body = request.getBody();
- if (body != null) {
- addBody(connection, request, body);
- }
- }
-
- private void addBody(HttpURLConnection connection, Request<?> request, byte[] body)
- throws IOException {
- // Prepare output. There is no need to set Content-Length explicitly,
- // since this is handled by HttpURLConnection using the size of the prepared
- // output stream.
- connection.setDoOutput(true);
- // Set the content-type unless it was already set (by Request#getHeaders).
- if (!connection.getRequestProperties().containsKey(HttpHeaderParser.HEADER_CONTENT_TYPE)) {
- connection.setRequestProperty(
- HttpHeaderParser.HEADER_CONTENT_TYPE, request.getBodyContentType());
- }
- DataOutputStream out =
- new DataOutputStream(createOutputStream(request, connection, body.length));
- out.write(body);
- out.close();
- }
-
- /**
- * Create and return an OutputStream to which the request body will be written.
- *
- * <p>May be overridden by subclasses to manipulate or monitor this output stream.
- *
- * @param request current request.
- * @param connection current connection of request.
- * @param length size of stream to write.
- * @return an OutputStream to which the request body will be written.
- * @throws IOException if an I/O error occurs while creating the stream.
- */
- protected OutputStream createOutputStream(
- Request<?> request, HttpURLConnection connection, int length) throws IOException {
- return connection.getOutputStream();
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/ImageLoader.java b/src/main/java/com/android/volley/toolbox/ImageLoader.java
deleted file mode 100644
index eece2cf..0000000
--- a/src/main/java/com/android/volley/toolbox/ImageLoader.java
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * 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
- *
- * 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.toolbox;
-
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.os.Handler;
-import android.os.Looper;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-import androidx.annotation.MainThread;
-import androidx.annotation.Nullable;
-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.List;
-
-/**
- * Helper that handles loading and caching images from remote URLs.
- *
- * <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. */
- private final RequestQueue mRequestQueue;
-
- /** Amount of time to wait after first response arrives before delivering all responses. */
- private int mBatchResponseDelayMs = 100;
-
- /** The cache implementation to be used as an L1 cache before calling into volley. */
- 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.
- */
- 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<>();
-
- /** Handler to the main thread. */
- private final Handler mHandler = new Handler(Looper.getMainLooper());
-
- /** Runnable for in-flight response delivery. */
- 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.
- */
- public interface ImageCache {
- @Nullable
- 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.
- */
- public ImageLoader(RequestQueue queue, ImageCache imageCache) {
- mRequestQueue = queue;
- mCache = imageCache;
- }
-
- /**
- * 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) {
- return new ImageListener() {
- @Override
- public void onErrorResponse(VolleyError error) {
- if (errorImageResId != 0) {
- view.setImageResource(errorImageResId);
- }
- }
-
- @Override
- public void onResponse(ImageContainer response, boolean isImmediate) {
- if (response.getBitmap() != null) {
- view.setImageBitmap(response.getBitmap());
- } else if (defaultImageResId != 0) {
- view.setImageResource(defaultImageResId);
- }
- }
- };
- }
-
- /**
- * Interface for the response handlers on image requests.
- *
- * <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.
- *
- * <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.
- */
- 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.
- * @return True if the item exists in cache, false otherwise.
- */
- public boolean isCached(String requestUrl, int maxWidth, int maxHeight) {
- return isCached(requestUrl, maxWidth, maxHeight, ScaleType.CENTER_INSIDE);
- }
-
- /**
- * 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.
- * @return True if the item exists in cache, false otherwise.
- */
- @MainThread
- public boolean isCached(String requestUrl, int maxWidth, int maxHeight, ScaleType scaleType) {
- Threads.throwIfNotOnMainThread();
-
- String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType);
- return mCache.getBitmap(cacheKey) != null;
- }
-
- /**
- * Returns an ImageContainer for the requested URL.
- *
- * <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, /* maxWidth= */ 0, /* maxHeight= */ 0);
- }
-
- /**
- * 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) {
- 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).
- *
- * <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).
- */
- @MainThread
- public ImageContainer get(
- String requestUrl,
- ImageListener imageListener,
- int maxWidth,
- int maxHeight,
- ScaleType scaleType) {
-
- // only fulfill requests that were initiated from the main thread.
- Threads.throwIfNotOnMainThread();
-
- final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType);
-
- // Try to look up the request in the cache of remote images.
- Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
- if (cachedBitmap != null) {
- // Return the cached bitmap.
- ImageContainer container =
- new ImageContainer(
- cachedBitmap, requestUrl, /* cacheKey= */ null, /* listener= */ null);
- imageListener.onResponse(container, true);
- return container;
- }
-
- // The bitmap did not exist in the cache, fetch it!
- ImageContainer imageContainer =
- new ImageContainer(null, requestUrl, cacheKey, imageListener);
-
- // Update the caller to let them know that they should use the default bitmap.
- imageListener.onResponse(imageContainer, true);
-
- // Check to see if a request is already in-flight or completed but pending batch delivery.
- BatchedImageRequest request = mInFlightRequests.get(cacheKey);
- if (request == null) {
- request = mBatchedResponses.get(cacheKey);
- }
- if (request != null) {
- // If it is, add this request to the list of listeners.
- request.addContainer(imageContainer);
- return imageContainer;
- }
-
- // 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);
-
- mRequestQueue.add(newRequest);
- 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);
- }
- });
- }
-
- /**
- * 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) {
- mBatchResponseDelayMs = newBatchedResponseDelayMs;
- }
-
- /**
- * 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.
- */
- protected void onGetImageSuccess(String cacheKey, Bitmap response) {
- // cache the image that was fetched.
- mCache.putBitmap(cacheKey, response);
-
- // remove the request from the list of in-flight requests.
- BatchedImageRequest request = mInFlightRequests.remove(cacheKey);
-
- if (request != null) {
- // Update the response bitmap.
- request.mResponseBitmap = response;
-
- // Send the batched response
- batchResponse(cacheKey, request);
- }
- }
-
- /**
- * 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) {
- // Notify the requesters that something failed via a null result.
- // Remove this request from the list of in-flight requests.
- BatchedImageRequest request = mInFlightRequests.remove(cacheKey);
-
- if (request != null) {
- // Set the error for this request
- request.setError(error);
-
- // Send the batched response
- batchResponse(cacheKey, 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).
- */
- private Bitmap mBitmap;
-
- private final ImageListener mListener;
-
- /** The cache key that was associated with the request */
- private final String mCacheKey;
-
- /** The request URL that was specified */
- private final String mRequestUrl;
-
- /**
- * 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) {
- mBitmap = bitmap;
- mRequestUrl = requestUrl;
- mCacheKey = cacheKey;
- mListener = listener;
- }
-
- /**
- * 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;
- }
-
- BatchedImageRequest request = mInFlightRequests.get(mCacheKey);
- if (request != null) {
- boolean canceled = request.removeContainerAndCancelIfNecessary(this);
- if (canceled) {
- mInFlightRequests.remove(mCacheKey);
- }
- } else {
- // check to see if it is already batched for delivery.
- request = mBatchedResponses.get(mCacheKey);
- if (request != null) {
- request.removeContainerAndCancelIfNecessary(this);
- if (request.mContainers.size() == 0) {
- mBatchedResponses.remove(mCacheKey);
- }
- }
- }
- }
-
- /**
- * Returns the bitmap associated with the request URL if it has been loaded, null otherwise.
- */
- public Bitmap getBitmap() {
- return mBitmap;
- }
-
- /** Returns the requested URL for this container. */
- public String getRequestUrl() {
- return mRequestUrl;
- }
- }
-
- /**
- * Wrapper class used to map a Request to the set of active ImageContainer objects that are
- * interested in its results.
- */
- private static class BatchedImageRequest {
- /** The request being tracked */
- private final Request<?> mRequest;
-
- /** The result of the request being tracked by this item */
- private Bitmap mResponseBitmap;
-
- /** Error if one occurred for this response */
- private VolleyError mError;
-
- /** List of all of the active ImageContainers that are interested in the request */
- 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.
- */
- public BatchedImageRequest(Request<?> request, ImageContainer container) {
- mRequest = request;
- mContainers.add(container);
- }
-
- /** Set the error for this response */
- public void setError(VolleyError error) {
- mError = error;
- }
-
- /** 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.
- */
- public void addContainer(ImageContainer container) {
- mContainers.add(container);
- }
-
- /**
- * 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.
- */
- public boolean removeContainerAndCancelIfNecessary(ImageContainer container) {
- mContainers.remove(container);
- if (mContainers.size() == 0) {
- mRequest.cancel();
- return true;
- }
- return false;
- }
- }
-
- /**
- * 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.
- */
- private void batchResponse(String cacheKey, BatchedImageRequest request) {
- mBatchedResponses.put(cacheKey, request);
- // 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());
- }
- }
- }
- mBatchedResponses.clear();
- mRunnable = null;
- }
- };
- // Post the runnable.
- mHandler.postDelayed(mRunnable, mBatchResponseDelayMs);
- }
- }
-
- /**
- * 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)
- .toString();
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/ImageRequest.java b/src/main/java/com/android/volley/toolbox/ImageRequest.java
deleted file mode 100644
index 32b5aa3..0000000
--- a/src/main/java/com/android/volley/toolbox/ImageRequest.java
+++ /dev/null
@@ -1,283 +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.toolbox;
-
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.BitmapFactory;
-import android.widget.ImageView.ScaleType;
-import androidx.annotation.GuardedBy;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-import com.android.volley.DefaultRetryPolicy;
-import com.android.volley.NetworkResponse;
-import com.android.volley.ParseError;
-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. */
-public class ImageRequest extends Request<Bitmap> {
- /** Socket timeout in milliseconds for image requests */
- public static final int DEFAULT_IMAGE_TIMEOUT_MS = 1000;
-
- /** Default number of retries for image requests */
- public static final int DEFAULT_IMAGE_MAX_RETRIES = 2;
-
- /** Default backoff multiplier for image requests */
- public static final float DEFAULT_IMAGE_BACKOFF_MULT = 2f;
-
- /** Lock to guard mListener as it is cleared on cancel() and read on delivery. */
- private final Object mLock = new Object();
-
- @GuardedBy("mLock")
- @Nullable
- private Response.Listener<Bitmap> mListener;
-
- private final Config mDecodeConfig;
- private final int mMaxWidth;
- private final int mMaxHeight;
- private final ScaleType mScaleType;
-
- /** Decoding lock so that we don't decode more than one image at a time (to avoid OOM's) */
- 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.
- *
- * @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 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,
- @Nullable Response.ErrorListener errorListener) {
- super(Method.GET, url, errorListener);
- setRetryPolicy(
- new DefaultRetryPolicy(
- DEFAULT_IMAGE_TIMEOUT_MS,
- DEFAULT_IMAGE_MAX_RETRIES,
- DEFAULT_IMAGE_BACKOFF_MULT));
- mListener = listener;
- mDecodeConfig = decodeConfig;
- mMaxWidth = maxWidth;
- mMaxHeight = maxHeight;
- mScaleType = scaleType;
- }
-
- /**
- * 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);
- }
-
- @Override
- public Priority getPriority() {
- return Priority.LOW;
- }
-
- /**
- * 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 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) {
-
- // If no dominant value at all, just return the actual.
- if ((maxPrimary == 0) && (maxSecondary == 0)) {
- return actualPrimary;
- }
-
- // If ScaleType.FIT_XY fill the whole rectangle, ignore ratio.
- if (scaleType == ScaleType.FIT_XY) {
- if (maxPrimary == 0) {
- return actualPrimary;
- }
- return maxPrimary;
- }
-
- // If primary is unspecified, scale primary to match secondary's scaling ratio.
- if (maxPrimary == 0) {
- double ratio = (double) maxSecondary / (double) actualSecondary;
- return (int) (actualPrimary * ratio);
- }
-
- if (maxSecondary == 0) {
- return maxPrimary;
- }
-
- double ratio = (double) actualSecondary / (double) actualPrimary;
- int resized = maxPrimary;
-
- // If ScaleType.CENTER_CROP fill the whole rectangle, preserve aspect ratio.
- if (scaleType == ScaleType.CENTER_CROP) {
- if ((resized * ratio) < maxSecondary) {
- resized = (int) (maxSecondary / ratio);
- }
- return resized;
- }
-
- if ((resized * ratio) > maxSecondary) {
- resized = (int) (maxSecondary / ratio);
- }
- return resized;
- }
-
- @Override
- protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
- // Serialize all decode on a global lock to reduce concurrent heap usage.
- synchronized (sDecodeLock) {
- try {
- return doParse(response);
- } catch (OutOfMemoryError e) {
- VolleyLog.e("Caught OOM for %d byte image, url=%s", response.data.length, getUrl());
- return Response.error(new ParseError(e));
- }
- }
- }
-
- /** 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();
- Bitmap bitmap = null;
- if (mMaxWidth == 0 && mMaxHeight == 0) {
- decodeOptions.inPreferredConfig = mDecodeConfig;
- bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
- } else {
- // If we have to resize this image, first get the natural bounds.
- decodeOptions.inJustDecodeBounds = true;
- BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
- int actualWidth = decodeOptions.outWidth;
- 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);
-
- // 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);
-
- // 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);
- tempBitmap.recycle();
- } else {
- bitmap = tempBitmap;
- }
- }
-
- if (bitmap == null) {
- return Response.error(new ParseError(response));
- } else {
- return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));
- }
- }
-
- @Override
- public void cancel() {
- super.cancel();
- synchronized (mLock) {
- mListener = null;
- }
- }
-
- @Override
- protected void deliverResponse(Bitmap response) {
- Response.Listener<Bitmap> listener;
- synchronized (mLock) {
- listener = mListener;
- }
- if (listener != null) {
- listener.onResponse(response);
- }
- }
-
- /**
- * 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
- */
- @VisibleForTesting
- static int findBestSampleSize(
- int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {
- double wr = (double) actualWidth / desiredWidth;
- double hr = (double) actualHeight / desiredHeight;
- double ratio = Math.min(wr, hr);
- float n = 1.0f;
- while ((n * 2) <= ratio) {
- n *= 2;
- }
-
- return (int) n;
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/JsonArrayRequest.java b/src/main/java/com/android/volley/toolbox/JsonArrayRequest.java
deleted file mode 100644
index 86ed9e9..0000000
--- a/src/main/java/com/android/volley/toolbox/JsonArrayRequest.java
+++ /dev/null
@@ -1,83 +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.toolbox;
-
-import androidx.annotation.Nullable;
-import com.android.volley.NetworkResponse;
-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;
-
-/** 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.
- */
- public JsonArrayRequest(
- String url, Listener<JSONArray> listener, @Nullable ErrorListener errorListener) {
- super(Method.GET, url, null, listener, errorListener);
- }
-
- /**
- * 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 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,
- @Nullable JSONArray jsonRequest,
- Listener<JSONArray> listener,
- @Nullable 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));
- } catch (UnsupportedEncodingException e) {
- return Response.error(new ParseError(e));
- } catch (JSONException je) {
- return Response.error(new ParseError(je));
- }
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/JsonObjectRequest.java b/src/main/java/com/android/volley/toolbox/JsonObjectRequest.java
deleted file mode 100644
index 8dca0ec..0000000
--- a/src/main/java/com/android/volley/toolbox/JsonObjectRequest.java
+++ /dev/null
@@ -1,93 +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.toolbox;
-
-import androidx.annotation.Nullable;
-import com.android.volley.NetworkResponse;
-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;
-
-/**
- * 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.
- */
-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 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,
- @Nullable JSONObject jsonRequest,
- Listener<JSONObject> listener,
- @Nullable 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.
- *
- * @see #JsonObjectRequest(int, String, JSONObject, Listener, ErrorListener)
- */
- public JsonObjectRequest(
- String url,
- @Nullable JSONObject jsonRequest,
- Listener<JSONObject> listener,
- @Nullable ErrorListener 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));
- } catch (UnsupportedEncodingException e) {
- return Response.error(new ParseError(e));
- } catch (JSONException je) {
- return Response.error(new ParseError(je));
- }
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/JsonRequest.java b/src/main/java/com/android/volley/toolbox/JsonRequest.java
deleted file mode 100644
index bc035ae..0000000
--- a/src/main/java/com/android/volley/toolbox/JsonRequest.java
+++ /dev/null
@@ -1,127 +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.toolbox;
-
-import androidx.annotation.GuardedBy;
-import androidx.annotation.Nullable;
-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.
- *
- * @param <T> JSON type of response expected
- */
-public abstract class JsonRequest<T> extends Request<T> {
- /** Default charset for JSON request. */
- protected static final String PROTOCOL_CHARSET = "utf-8";
-
- /** Content type for request. */
- private static final String PROTOCOL_CONTENT_TYPE =
- 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();
-
- @Nullable
- @GuardedBy("mLock")
- private Listener<T> mListener;
-
- @Nullable private final String mRequestBody;
-
- /**
- * Deprecated constructor for a JsonRequest which defaults to GET unless {@link #getPostBody()}
- * or {@link #getPostParams()} is overridden (which defaults to POST).
- *
- * @deprecated Use {@link #JsonRequest(int, String, String, Listener, ErrorListener)}.
- */
- @Deprecated
- 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,
- @Nullable String requestBody,
- Listener<T> listener,
- @Nullable ErrorListener errorListener) {
- super(method, url, errorListener);
- mListener = listener;
- mRequestBody = requestBody;
- }
-
- @Override
- public void cancel() {
- super.cancel();
- synchronized (mLock) {
- mListener = null;
- }
- }
-
- @Override
- protected void deliverResponse(T response) {
- Response.Listener<T> listener;
- synchronized (mLock) {
- listener = mListener;
- }
- if (listener != null) {
- listener.onResponse(response);
- }
- }
-
- @Override
- protected abstract Response<T> parseNetworkResponse(NetworkResponse response);
-
- /** @deprecated Use {@link #getBodyContentType()}. */
- @Deprecated
- @Override
- public String getPostBodyContentType() {
- return getBodyContentType();
- }
-
- /** @deprecated Use {@link #getBody()}. */
- @Deprecated
- @Override
- public byte[] getPostBody() {
- return getBody();
- }
-
- @Override
- public String getBodyContentType() {
- return PROTOCOL_CONTENT_TYPE;
- }
-
- @Override
- public byte[] getBody() {
- 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",
- 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
deleted file mode 100644
index a24b3e2..0000000
--- a/src/main/java/com/android/volley/toolbox/NetworkImageView.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/**
- * Copyright (C) 2013 The Android Open Source Project
- *
- * <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
- *
- * <p>http://www.apache.org/licenses/LICENSE-2.0
- *
- * <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.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.ImageView;
-import androidx.annotation.MainThread;
-import androidx.annotation.Nullable;
-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. */
-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. Won't
- * be set at the same time as mDefaultImageDrawable or mDefaultImageBitmap.
- */
- private int mDefaultImageId;
-
- /**
- * Drawable of the image to be used as a placeholder until the network image is loaded. Won't be
- * set at the same time as mDefaultImageId or mDefaultImageBitmap.
- */
- @Nullable private Drawable mDefaultImageDrawable;
-
- /**
- * Bitmap of the image to be used as a placeholder until the network image is loaded. Won't be
- * set at the same time as mDefaultImageId or mDefaultImageDrawable.
- */
- @Nullable private Bitmap mDefaultImageBitmap;
-
- /**
- * Resource ID of the image to be used if the network response fails. Won't be set at the same
- * time as mErrorImageDrawable or mErrorImageBitmap.
- */
- private int mErrorImageId;
-
- /**
- * Bitmap of the image to be used if the network response fails. Won't be set at the same time
- * as mErrorImageId or mErrorImageBitmap.
- */
- @Nullable private Drawable mErrorImageDrawable;
-
- /**
- * Bitmap of the image to be used if the network response fails. Won't be set at the same time
- * as mErrorImageId or mErrorImageDrawable.
- */
- @Nullable private Bitmap mErrorImageBitmap;
-
- /** Local copy of the ImageLoader. */
- private ImageLoader mImageLoader;
-
- /** Current ImageContainer. (either in-flight or finished) */
- private ImageContainer mImageContainer;
-
- public NetworkImageView(Context context) {
- this(context, null);
- }
-
- public NetworkImageView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public NetworkImageView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- /**
- * Sets URL of the image that should be loaded into this view. Note that calling this will
- * immediately either set the cached image (if available) or the default image specified by
- * {@link NetworkImageView#setDefaultImageResId(int)} on the view.
- *
- * <p>NOTE: If applicable, {@link NetworkImageView#setDefaultImageResId(int)} or {@link
- * NetworkImageView#setDefaultImageBitmap} and {@link NetworkImageView#setErrorImageResId(int)}
- * or {@link NetworkImageView#setErrorImageBitmap(Bitmap)} 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(/* isInLayoutPass= */ false);
- }
-
- /**
- * Sets the default image resource ID to be used for this view until the attempt to load it
- * completes.
- *
- * <p>This will clear anything set by {@link NetworkImageView#setDefaultImageBitmap} or {@link
- * NetworkImageView#setDefaultImageDrawable}.
- */
- public void setDefaultImageResId(int defaultImage) {
- mDefaultImageBitmap = null;
- mDefaultImageDrawable = null;
- mDefaultImageId = defaultImage;
- }
-
- /**
- * Sets the default image drawable to be used for this view until the attempt to load it
- * completes.
- *
- * <p>This will clear anything set by {@link NetworkImageView#setDefaultImageResId} or {@link
- * NetworkImageView#setDefaultImageBitmap}.
- */
- public void setDefaultImageDrawable(@Nullable Drawable defaultImageDrawable) {
- mDefaultImageId = 0;
- mDefaultImageBitmap = null;
- mDefaultImageDrawable = defaultImageDrawable;
- }
-
- /**
- * Sets the default image bitmap to be used for this view until the attempt to load it
- * completes.
- *
- * <p>This will clear anything set by {@link NetworkImageView#setDefaultImageResId} or {@link
- * NetworkImageView#setDefaultImageDrawable}.
- */
- public void setDefaultImageBitmap(Bitmap defaultImage) {
- mDefaultImageId = 0;
- mDefaultImageDrawable = null;
- mDefaultImageBitmap = defaultImage;
- }
-
- /**
- * Sets the error image resource ID to be used for this view in the event that the image
- * requested fails to load.
- *
- * <p>This will clear anything set by {@link NetworkImageView#setErrorImageBitmap} or {@link
- * NetworkImageView#setErrorImageDrawable}.
- */
- public void setErrorImageResId(int errorImage) {
- mErrorImageBitmap = null;
- mErrorImageDrawable = null;
- mErrorImageId = errorImage;
- }
-
- /**
- * Sets the error image drawable to be used for this view in the event that the image requested
- * fails to load.
- *
- * <p>This will clear anything set by {@link NetworkImageView#setErrorImageResId} or {@link
- * NetworkImageView#setDefaultImageBitmap}.
- */
- public void setErrorImageDrawable(@Nullable Drawable errorImageDrawable) {
- mErrorImageId = 0;
- mErrorImageBitmap = null;
- mErrorImageDrawable = errorImageDrawable;
- }
-
- /**
- * Sets the error image bitmap to be used for this view in the event that the image requested
- * fails to load.
- *
- * <p>This will clear anything set by {@link NetworkImageView#setErrorImageResId} or {@link
- * NetworkImageView#setDefaultImageDrawable}.
- */
- public void setErrorImageBitmap(Bitmap errorImage) {
- mErrorImageId = 0;
- mErrorImageDrawable = null;
- mErrorImageBitmap = errorImage;
- }
-
- /**
- * 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) {
- int width = getWidth();
- int height = getHeight();
- ScaleType scaleType = getScaleType();
-
- boolean wrapWidth = false, wrapHeight = false;
- if (getLayoutParams() != null) {
- wrapWidth = getLayoutParams().width == LayoutParams.WRAP_CONTENT;
- wrapHeight = getLayoutParams().height == LayoutParams.WRAP_CONTENT;
- }
-
- // if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content
- // view, hold off on loading the image.
- boolean isFullyWrapContent = wrapWidth && wrapHeight;
- if (width == 0 && height == 0 && !isFullyWrapContent) {
- return;
- }
-
- // if the URL to be loaded in this view is empty, cancel any old requests and clear the
- // currently loaded image.
- if (TextUtils.isEmpty(mUrl)) {
- if (mImageContainer != null) {
- mImageContainer.cancelRequest();
- mImageContainer = null;
- }
- setDefaultImageOrNull();
- return;
- }
-
- // if there was an old request in this view, check if it needs to be canceled.
- if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {
- if (mImageContainer.getRequestUrl().equals(mUrl)) {
- // if the request is from the same URL, return.
- return;
- } else {
- // if there is a pre-existing request, cancel it if it's fetching a different URL.
- mImageContainer.cancelRequest();
- setDefaultImageOrNull();
- }
- }
-
- // Calculate the max image width / height to use while ignoring WRAP_CONTENT dimens.
- int maxWidth = wrapWidth ? 0 : width;
- int maxHeight = wrapHeight ? 0 : height;
-
- // The pre-existing content of this view didn't match the current URL. Load the new image
- // 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);
- } else if (mErrorImageDrawable != null) {
- setImageDrawable(mErrorImageDrawable);
- } else if (mErrorImageBitmap != null) {
- setImageBitmap(mErrorImageBitmap);
- }
- }
-
- @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;
- }
-
- if (response.getBitmap() != null) {
- setImageBitmap(response.getBitmap());
- } else if (mDefaultImageId != 0) {
- setImageResource(mDefaultImageId);
- } else if (mDefaultImageDrawable != null) {
- setImageDrawable(mDefaultImageDrawable);
- } else if (mDefaultImageBitmap != null) {
- setImageBitmap(mDefaultImageBitmap);
- }
- }
- },
- maxWidth,
- maxHeight,
- scaleType);
- }
-
- private void setDefaultImageOrNull() {
- if (mDefaultImageId != 0) {
- setImageResource(mDefaultImageId);
- } else if (mDefaultImageDrawable != null) {
- setImageDrawable(mDefaultImageDrawable);
- } else if (mDefaultImageBitmap != null) {
- setImageBitmap(mDefaultImageBitmap);
- } else {
- setImageBitmap(null);
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- loadImageIfNecessary(/* isInLayoutPass= */ true);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- if (mImageContainer != null) {
- // If the view was bound to an image request, cancel it and clear
- // out the image from the view.
- mImageContainer.cancelRequest();
- setImageBitmap(null);
- // also clear out the container so we can reload the image if necessary.
- mImageContainer = null;
- }
- super.onDetachedFromWindow();
- }
-
- @Override
- protected void drawableStateChanged() {
- super.drawableStateChanged();
- invalidate();
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/NetworkUtility.java b/src/main/java/com/android/volley/toolbox/NetworkUtility.java
deleted file mode 100644
index 44d5904..0000000
--- a/src/main/java/com/android/volley/toolbox/NetworkUtility.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2020 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.toolbox;
-
-import android.os.SystemClock;
-import androidx.annotation.Nullable;
-import com.android.volley.AuthFailureError;
-import com.android.volley.Cache;
-import com.android.volley.ClientError;
-import com.android.volley.Header;
-import com.android.volley.NetworkError;
-import com.android.volley.NetworkResponse;
-import com.android.volley.NoConnectionError;
-import com.android.volley.Request;
-import com.android.volley.RetryPolicy;
-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;
-import java.net.MalformedURLException;
-import java.net.SocketTimeoutException;
-import java.util.List;
-
-/**
- * Utility class for methods that are shared between {@link BasicNetwork} and {@link
- * BasicAsyncNetwork}
- */
-public final class NetworkUtility {
- private static final int SLOW_REQUEST_THRESHOLD_MS = 3000;
-
- private NetworkUtility() {}
-
- /** Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete. */
- static void logSlowRequests(
- long requestLifetime, Request<?> request, byte[] responseContents, int statusCode) {
- if (VolleyLog.DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) {
- 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());
- }
- }
-
- static NetworkResponse getNotModifiedNetworkResponse(
- Request<?> request, long requestDuration, List<Header> responseHeaders) {
- Cache.Entry entry = request.getCacheEntry();
- if (entry == null) {
- return new NetworkResponse(
- HttpURLConnection.HTTP_NOT_MODIFIED,
- /* data= */ null,
- /* notModified= */ true,
- requestDuration,
- responseHeaders);
- }
- // Combine cached and response headers so the response will be complete.
- List<Header> combinedHeaders = HttpHeaderParser.combineHeaders(responseHeaders, entry);
- return new NetworkResponse(
- HttpURLConnection.HTTP_NOT_MODIFIED,
- entry.data,
- /* notModified= */ true,
- requestDuration,
- combinedHeaders);
- }
-
- /** Reads the contents of an InputStream into a byte[]. */
- static byte[] inputStreamToBytes(InputStream in, int contentLength, ByteArrayPool pool)
- throws IOException {
- PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(pool, contentLength);
- byte[] buffer = null;
- try {
- buffer = pool.getBuf(1024);
- int count;
- while ((count = in.read(buffer)) != -1) {
- bytes.write(buffer, 0, count);
- }
- return bytes.toByteArray();
- } finally {
- try {
- // Close the InputStream and release the resources by "consuming the content".
- if (in != null) {
- in.close();
- }
- } catch (IOException e) {
- // This can happen if there was an exception above that left the stream in
- // an invalid state.
- VolleyLog.v("Error occurred when closing InputStream");
- }
- pool.returnBuf(buffer);
- bytes.close();
- }
- }
-
- /**
- * 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(
- final String logPrefix, final Request<?> request, final VolleyError exception)
- throws VolleyError {
- final RetryPolicy retryPolicy = request.getRetryPolicy();
- final int oldTimeout = request.getTimeoutMs();
- try {
- retryPolicy.retry(exception);
- } catch (VolleyError e) {
- request.addMarker(
- String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));
- throw e;
- }
- request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));
- }
-
- /**
- * Based on the exception thrown, decides whether to attempt to retry, or to throw the error.
- * Also handles logging.
- */
- static void handleException(
- Request<?> request,
- IOException exception,
- long requestStartMs,
- @Nullable HttpResponse httpResponse,
- @Nullable byte[] responseContents)
- throws VolleyError {
- if (exception instanceof SocketTimeoutException) {
- attemptRetryOnException("socket", request, new TimeoutError());
- } else if (exception instanceof MalformedURLException) {
- throw new RuntimeException("Bad URL " + request.getUrl(), exception);
- } else {
- int statusCode;
- if (httpResponse != null) {
- statusCode = httpResponse.getStatusCode();
- } else {
- if (request.shouldRetryConnectionErrors()) {
- attemptRetryOnException("connection", request, new NoConnectionError());
- return;
- } else {
- throw new NoConnectionError(exception);
- }
- }
- VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
- NetworkResponse networkResponse;
- if (responseContents != null) {
- List<Header> responseHeaders;
- responseHeaders = httpResponse.getHeaders();
- networkResponse =
- new NetworkResponse(
- statusCode,
- responseContents,
- /* notModified= */ false,
- SystemClock.elapsedRealtime() - requestStartMs,
- 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));
- } else {
- throw new ServerError(networkResponse);
- }
- } else {
- // 3xx? No reason to retry.
- throw new ServerError(networkResponse);
- }
- } else {
- attemptRetryOnException("network", request, new NetworkError());
- }
- }
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/NoAsyncCache.java b/src/main/java/com/android/volley/toolbox/NoAsyncCache.java
deleted file mode 100644
index aa4aeea..0000000
--- a/src/main/java/com/android/volley/toolbox/NoAsyncCache.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.android.volley.toolbox;
-
-import com.android.volley.AsyncCache;
-import com.android.volley.Cache;
-
-/** An AsyncCache that doesn't cache anything. */
-public class NoAsyncCache extends AsyncCache {
- @Override
- public void get(String key, OnGetCompleteCallback callback) {
- callback.onGetComplete(null);
- }
-
- @Override
- public void put(String key, Cache.Entry entry, OnWriteCompleteCallback callback) {
- callback.onWriteComplete();
- }
-
- @Override
- public void clear(OnWriteCompleteCallback callback) {
- callback.onWriteComplete();
- }
-
- @Override
- public void initialize(OnWriteCompleteCallback callback) {
- callback.onWriteComplete();
- }
-
- @Override
- public void invalidate(String key, boolean fullExpire, OnWriteCompleteCallback callback) {
- callback.onWriteComplete();
- }
-
- @Override
- public void remove(String key, OnWriteCompleteCallback callback) {
- callback.onWriteComplete();
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/NoCache.java b/src/main/java/com/android/volley/toolbox/NoCache.java
deleted file mode 100644
index 51f9945..0000000
--- a/src/main/java/com/android/volley/toolbox/NoCache.java
+++ /dev/null
@@ -1,42 +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.toolbox;
-
-import com.android.volley.Cache;
-
-/** A cache that doesn't. */
-public class NoCache implements Cache {
- @Override
- public void clear() {}
-
- @Override
- public Entry get(String key) {
- return null;
- }
-
- @Override
- public void put(String key, Entry entry) {}
-
- @Override
- public void invalidate(String key, boolean fullExpire) {}
-
- @Override
- public void remove(String key) {}
-
- @Override
- 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
deleted file mode 100644
index bdcc45e..0000000
--- a/src/main/java/com/android/volley/toolbox/PoolingByteArrayOutputStream.java
+++ /dev/null
@@ -1,92 +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.toolbox;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-/**
- * A variation of {@link java.io.ByteArrayOutputStream} that uses a pool of byte[] buffers instead
- * of always allocating them fresh, saving on heap churn.
- */
-public class PoolingByteArrayOutputStream extends ByteArrayOutputStream {
- /**
- * If the {@link #PoolingByteArrayOutputStream(ByteArrayPool)} constructor is called, this is
- * the default size to which the underlying byte array is initialized.
- */
- private static final int DEFAULT_SIZE = 256;
-
- private final ByteArrayPool mPool;
-
- /**
- * Constructs a new PoolingByteArrayOutputStream with a default size. If more bytes are written
- * to this instance, the underlying byte array will expand.
- */
- public PoolingByteArrayOutputStream(ByteArrayPool pool) {
- this(pool, DEFAULT_SIZE);
- }
-
- /**
- * Constructs a new {@code ByteArrayOutputStream} with a default size of {@code size} bytes. If
- * more than {@code size} bytes are written to this instance, the underlying byte array will
- * expand.
- *
- * @param size initial size for the underlying byte array. The value will be pinned to a default
- * minimum size.
- */
- public PoolingByteArrayOutputStream(ByteArrayPool pool, int size) {
- mPool = pool;
- buf = mPool.getBuf(Math.max(size, DEFAULT_SIZE));
- }
-
- @Override
- public void close() throws IOException {
- mPool.returnBuf(buf);
- buf = null;
- super.close();
- }
-
- @Override
- public void finalize() {
- mPool.returnBuf(buf);
- }
-
- /** 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) {
- return;
- }
- byte[] newbuf = mPool.getBuf((count + i) * 2);
- System.arraycopy(buf, 0, newbuf, 0, count);
- mPool.returnBuf(buf);
- buf = newbuf;
- }
-
- @Override
- public synchronized void write(byte[] buffer, int offset, int len) {
- expand(len);
- super.write(buffer, offset, len);
- }
-
- @Override
- public synchronized void write(int oneByte) {
- expand(1);
- super.write(oneByte);
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/RequestFuture.java b/src/main/java/com/android/volley/toolbox/RequestFuture.java
deleted file mode 100644
index f9cbce2..0000000
--- a/src/main/java/com/android/volley/toolbox/RequestFuture.java
+++ /dev/null
@@ -1,159 +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.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;
-import java.util.concurrent.TimeoutException;
-
-/**
- * A Future that represents a Volley request.
- *
- * <p>Used by providing as your response and error listeners. For example:
- *
- * <pre>
- * RequestFuture&lt;JSONObject&gt; future = RequestFuture.newFuture();
- * MyRequest request = new MyRequest(URL, future, future);
- *
- * // If you want to be able to cancel the request:
- * future.setRequest(requestQueue.add(request));
- *
- * // Otherwise:
- * requestQueue.add(request);
- *
- * try {
- * JSONObject response = future.get();
- * // do something with response
- * } catch (InterruptedException e) {
- * // handle the error
- * } catch (ExecutionException e) {
- * // handle the error
- * }
- * </pre>
- *
- * @param <T> The type of parsed response this future expects.
- */
-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<>();
- }
-
- private RequestFuture() {}
-
- public void setRequest(Request<?> request) {
- mRequest = request;
- }
-
- @Override
- public synchronized boolean cancel(boolean mayInterruptIfRunning) {
- if (mRequest == null) {
- return false;
- }
-
- if (!isDone()) {
- mRequest.cancel();
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- public T get() throws InterruptedException, ExecutionException {
- try {
- return doGet(/* timeoutMs= */ null);
- } catch (TimeoutException e) {
- throw new AssertionError(e);
- }
- }
-
- @Override
- public T get(long timeout, TimeUnit unit)
- throws InterruptedException, ExecutionException, TimeoutException {
- return doGet(TimeUnit.MILLISECONDS.convert(timeout, unit));
- }
-
- private synchronized T doGet(Long timeoutMs)
- throws InterruptedException, ExecutionException, TimeoutException {
- if (mException != null) {
- throw new ExecutionException(mException);
- }
-
- if (mResultReceived) {
- return mResult;
- }
-
- if (timeoutMs == null) {
- while (!isDone()) {
- wait(0);
- }
- } else if (timeoutMs > 0) {
- long nowMs = SystemClock.uptimeMillis();
- long deadlineMs = nowMs + timeoutMs;
- while (!isDone() && nowMs < deadlineMs) {
- wait(deadlineMs - nowMs);
- nowMs = SystemClock.uptimeMillis();
- }
- }
-
- if (mException != null) {
- throw new ExecutionException(mException);
- }
-
- if (!mResultReceived) {
- throw new TimeoutException();
- }
-
- return mResult;
- }
-
- @Override
- public boolean isCancelled() {
- if (mRequest == null) {
- return false;
- }
- return mRequest.isCanceled();
- }
-
- @Override
- public synchronized boolean isDone() {
- return mResultReceived || mException != null || isCancelled();
- }
-
- @Override
- public synchronized void onResponse(T response) {
- mResultReceived = true;
- mResult = response;
- notifyAll();
- }
-
- @Override
- public synchronized void onErrorResponse(VolleyError error) {
- mException = error;
- notifyAll();
- }
-}
diff --git a/src/main/java/com/android/volley/toolbox/StringRequest.java b/src/main/java/com/android/volley/toolbox/StringRequest.java
deleted file mode 100644
index df7b386..0000000
--- a/src/main/java/com/android/volley/toolbox/StringRequest.java
+++ /dev/null
@@ -1,100 +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.toolbox;
-
-import androidx.annotation.GuardedBy;
-import androidx.annotation.Nullable;
-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. */
-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();
-
- @Nullable
- @GuardedBy("mLock")
- private Listener<String> mListener;
-
- /**
- * Creates a new request with the given method.
- *
- * @param method the request {@link Method} to use
- * @param url URL to fetch the string at
- * @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,
- @Nullable ErrorListener errorListener) {
- super(method, url, errorListener);
- mListener = listener;
- }
-
- /**
- * Creates a new GET request.
- *
- * @param url URL to fetch the string at
- * @param listener Listener to receive the String response
- * @param errorListener Error listener, or null to ignore errors
- */
- public StringRequest(
- String url, Listener<String> listener, @Nullable ErrorListener errorListener) {
- this(Method.GET, url, listener, errorListener);
- }
-
- @Override
- public void cancel() {
- super.cancel();
- synchronized (mLock) {
- mListener = null;
- }
- }
-
- @Override
- protected void deliverResponse(String response) {
- Response.Listener<String> listener;
- synchronized (mLock) {
- listener = mListener;
- }
- if (listener != null) {
- listener.onResponse(response);
- }
- }
-
- @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
deleted file mode 100644
index 66c3e41..0000000
--- a/src/main/java/com/android/volley/toolbox/Threads.java
+++ /dev/null
@@ -1,13 +0,0 @@
-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/UrlRewriter.java b/src/main/java/com/android/volley/toolbox/UrlRewriter.java
deleted file mode 100644
index 8bbb770..0000000
--- a/src/main/java/com/android/volley/toolbox/UrlRewriter.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2020 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.toolbox;
-
-import androidx.annotation.Nullable;
-
-/** 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.
- */
- @Nullable
- String rewriteUrl(String originalUrl);
-}
diff --git a/src/main/java/com/android/volley/toolbox/Volley.java b/src/main/java/com/android/volley/toolbox/Volley.java
deleted file mode 100644
index bc65c9c..0000000
--- a/src/main/java/com/android/volley/toolbox/Volley.java
+++ /dev/null
@@ -1,118 +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.toolbox;
-
-import android.content.Context;
-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 {
-
- /** Default on-disk cache directory. */
- private static final String DEFAULT_CACHE_DIR = "volley";
-
- /**
- * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
- *
- * @param context A {@link Context} to use for creating the cache dir.
- * @param stack A {@link BaseHttpStack} to use for the network, or null for default.
- * @return A started {@link RequestQueue} instance.
- */
- public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
- BasicNetwork network;
- if (stack == null) {
- if (Build.VERSION.SDK_INT >= 9) {
- network = new BasicNetwork(new HurlStack());
- } else {
- // Prior to Gingerbread, HttpUrlConnection was unreliable.
- // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
- // At some point in the future we'll move our minSdkVersion past Froyo and can
- // delete this fallback (along with all Apache HTTP code).
- String userAgent = "volley/0";
- try {
- String packageName = context.getPackageName();
- PackageInfo info =
- context.getPackageManager().getPackageInfo(packageName, /* flags= */ 0);
- userAgent = packageName + "/" + info.versionCode;
- } catch (NameNotFoundException e) {
- }
-
- network =
- new BasicNetwork(
- new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
- }
- } else {
- network = new BasicNetwork(stack);
- }
-
- return newRequestQueue(context, network);
- }
-
- /**
- * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
- *
- * @param context A {@link Context} to use for creating the cache dir.
- * @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.
- */
- @Deprecated
- @SuppressWarnings("deprecation")
- public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
- if (stack == null) {
- return newRequestQueue(context, (BaseHttpStack) null);
- }
- return newRequestQueue(context, new BasicNetwork(stack));
- }
-
- private static RequestQueue newRequestQueue(Context context, Network network) {
- final Context appContext = context.getApplicationContext();
- // Use a lazy supplier for the cache directory so that newRequestQueue() can be called on
- // main thread without causing strict mode violation.
- DiskBasedCache.FileSupplier cacheSupplier =
- new DiskBasedCache.FileSupplier() {
- private File cacheDir = null;
-
- @Override
- public File get() {
- if (cacheDir == null) {
- cacheDir = new File(appContext.getCacheDir(), DEFAULT_CACHE_DIR);
- }
- return cacheDir;
- }
- };
- RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheSupplier), network);
- queue.start();
- return queue;
- }
-
- /**
- * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
- *
- * @param context A {@link Context} to use for creating the cache dir.
- * @return A started {@link RequestQueue} instance.
- */
- public static RequestQueue newRequestQueue(Context context) {
- return newRequestQueue(context, (BaseHttpStack) null);
- }
-}