aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com')
-rw-r--r--src/main/java/com/android/volley/Cache.java3
-rw-r--r--src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java15
-rw-r--r--src/main/java/com/android/volley/toolbox/BasicNetwork.java4
-rw-r--r--src/main/java/com/android/volley/toolbox/DiskBasedCache.java13
-rw-r--r--src/main/java/com/android/volley/toolbox/HttpHeaderParser.java18
-rw-r--r--src/main/java/com/android/volley/toolbox/ImageLoader.java23
-rw-r--r--src/main/java/com/android/volley/toolbox/ImageRequest.java47
-rw-r--r--src/main/java/com/android/volley/toolbox/NetworkImageView.java3
8 files changed, 105 insertions, 21 deletions
diff --git a/src/main/java/com/android/volley/Cache.java b/src/main/java/com/android/volley/Cache.java
index eafd118..f1ec757 100644
--- a/src/main/java/com/android/volley/Cache.java
+++ b/src/main/java/com/android/volley/Cache.java
@@ -74,6 +74,9 @@ public interface Cache {
/** 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;
diff --git a/src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java b/src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java
index 371fd83..bdf7091 100644
--- a/src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java
+++ b/src/main/java/com/android/volley/toolbox/AndroidAuthenticator.java
@@ -30,7 +30,7 @@ import android.os.Bundle;
* tokens of a specified type for a specified account.
*/
public class AndroidAuthenticator implements Authenticator {
- private final Context mContext;
+ private final AccountManager mAccountManager;
private final Account mAccount;
private final String mAuthTokenType;
private final boolean mNotifyAuthFailure;
@@ -54,7 +54,13 @@ public class AndroidAuthenticator implements Authenticator {
*/
public AndroidAuthenticator(Context context, Account account, String authTokenType,
boolean notifyAuthFailure) {
- mContext = context;
+ this(AccountManager.get(context), account, authTokenType, notifyAuthFailure);
+ }
+
+ // Visible for testing. Allows injection of a mock AccountManager.
+ AndroidAuthenticator(AccountManager accountManager, Account account,
+ String authTokenType, boolean notifyAuthFailure) {
+ mAccountManager = accountManager;
mAccount = account;
mAuthTokenType = authTokenType;
mNotifyAuthFailure = notifyAuthFailure;
@@ -71,8 +77,7 @@ public class AndroidAuthenticator implements Authenticator {
@SuppressWarnings("deprecation")
@Override
public String getAuthToken() throws AuthFailureError {
- final AccountManager accountManager = AccountManager.get(mContext);
- AccountManagerFuture<Bundle> future = accountManager.getAuthToken(mAccount,
+ AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(mAccount,
mAuthTokenType, mNotifyAuthFailure, null, null);
Bundle result;
try {
@@ -97,6 +102,6 @@ public class AndroidAuthenticator implements Authenticator {
@Override
public void invalidateAuthToken(String authToken) {
- AccountManager.get(mContext).invalidateAuthToken(mAccount.type, authToken);
+ mAccountManager.invalidateAuthToken(mAccount.type, authToken);
}
}
diff --git a/src/main/java/com/android/volley/toolbox/BasicNetwork.java b/src/main/java/com/android/volley/toolbox/BasicNetwork.java
index bc1cfdb..4b1603b 100644
--- a/src/main/java/com/android/volley/toolbox/BasicNetwork.java
+++ b/src/main/java/com/android/volley/toolbox/BasicNetwork.java
@@ -212,8 +212,8 @@ public class BasicNetwork implements Network {
headers.put("If-None-Match", entry.etag);
}
- if (entry.serverDate > 0) {
- Date refTime = new Date(entry.serverDate);
+ if (entry.lastModified > 0) {
+ Date refTime = new Date(entry.lastModified);
headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
}
}
diff --git a/src/main/java/com/android/volley/toolbox/DiskBasedCache.java b/src/main/java/com/android/volley/toolbox/DiskBasedCache.java
index b283788..036b55a 100644
--- a/src/main/java/com/android/volley/toolbox/DiskBasedCache.java
+++ b/src/main/java/com/android/volley/toolbox/DiskBasedCache.java
@@ -349,6 +349,9 @@ public class DiskBasedCache implements Cache {
/** 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;
@@ -370,6 +373,7 @@ public class DiskBasedCache implements Cache {
this.size = entry.data.length;
this.etag = entry.etag;
this.serverDate = entry.serverDate;
+ this.lastModified = entry.lastModified;
this.ttl = entry.ttl;
this.softTtl = entry.softTtl;
this.responseHeaders = entry.responseHeaders;
@@ -396,6 +400,13 @@ public class DiskBasedCache implements Cache {
entry.ttl = readLong(is);
entry.softTtl = readLong(is);
entry.responseHeaders = readStringStringMap(is);
+
+ try {
+ entry.lastModified = readLong(is);
+ } catch (EOFException e) {
+ // the old cache entry format doesn't know lastModified
+ }
+
return entry;
}
@@ -407,6 +418,7 @@ public class DiskBasedCache implements Cache {
e.data = data;
e.etag = etag;
e.serverDate = serverDate;
+ e.lastModified = lastModified;
e.ttl = ttl;
e.softTtl = softTtl;
e.responseHeaders = responseHeaders;
@@ -426,6 +438,7 @@ public class DiskBasedCache implements Cache {
writeLong(os, ttl);
writeLong(os, softTtl);
writeStringStringMap(responseHeaders, os);
+ writeLong(os, lastModified);
os.flush();
return true;
} catch (IOException e) {
diff --git a/src/main/java/com/android/volley/toolbox/HttpHeaderParser.java b/src/main/java/com/android/volley/toolbox/HttpHeaderParser.java
index 601ac0f..7306052 100644
--- a/src/main/java/com/android/volley/toolbox/HttpHeaderParser.java
+++ b/src/main/java/com/android/volley/toolbox/HttpHeaderParser.java
@@ -42,9 +42,12 @@ public class HttpHeaderParser {
Map<String, String> headers = response.headers;
long serverDate = 0;
+ long lastModified = 0;
long serverExpires = 0;
long softExpire = 0;
+ long finalExpire = 0;
long maxAge = 0;
+ long staleWhileRevalidate = 0;
boolean hasCacheControl = false;
String serverEtag = null;
@@ -68,6 +71,11 @@ public class HttpHeaderParser {
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")) {
maxAge = 0;
}
@@ -79,23 +87,31 @@ public class HttpHeaderParser {
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 = 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 = entry.softTtl;
+ entry.ttl = finalExpire;
entry.serverDate = serverDate;
+ entry.lastModified = lastModified;
entry.responseHeaders = headers;
return entry;
diff --git a/src/main/java/com/android/volley/toolbox/ImageLoader.java b/src/main/java/com/android/volley/toolbox/ImageLoader.java
index 5348dc6..151e022 100644
--- a/src/main/java/com/android/volley/toolbox/ImageLoader.java
+++ b/src/main/java/com/android/volley/toolbox/ImageLoader.java
@@ -20,6 +20,7 @@ import android.graphics.Bitmap.Config;
import android.os.Handler;
import android.os.Looper;
import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
@@ -171,6 +172,15 @@ public class ImageLoader {
}
/**
+ * 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
@@ -179,11 +189,13 @@ public class ImageLoader {
* @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).
*/
public ImageContainer get(String requestUrl, ImageListener imageListener,
- int maxWidth, int maxHeight) {
+ int maxWidth, int maxHeight, ScaleType scaleType) {
+
// only fulfill requests that were initiated from the main thread.
throwIfNotOnMainThread();
@@ -215,7 +227,8 @@ public class ImageLoader {
// The request is not already in flight. Send the new request to the network and
// track it.
- Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, cacheKey);
+ Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType,
+ cacheKey);
mRequestQueue.add(newRequest);
mInFlightRequests.put(cacheKey,
@@ -223,14 +236,14 @@ public class ImageLoader {
return imageContainer;
}
- protected Request<Bitmap> makeImageRequest(String requestUrl, int maxWidth, int maxHeight, final String cacheKey) {
+ 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,
- Config.RGB_565, new ErrorListener() {
+ }, maxWidth, maxHeight, scaleType, Config.RGB_565, new ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
onGetImageError(cacheKey, error);
diff --git a/src/main/java/com/android/volley/toolbox/ImageRequest.java b/src/main/java/com/android/volley/toolbox/ImageRequest.java
index 2ebe015..27c1fe2 100644
--- a/src/main/java/com/android/volley/toolbox/ImageRequest.java
+++ b/src/main/java/com/android/volley/toolbox/ImageRequest.java
@@ -26,6 +26,7 @@ import com.android.volley.VolleyLog;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
+import android.widget.ImageView.ScaleType;
/**
* A canned request for getting an image at a given URL and calling
@@ -45,6 +46,7 @@ public class ImageRequest extends Request<Bitmap> {
private final Config mDecodeConfig;
private final int mMaxWidth;
private final int mMaxHeight;
+ private 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();
@@ -63,20 +65,32 @@ public class ImageRequest extends Request<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,
- Config decodeConfig, Response.ErrorListener errorListener) {
- super(Method.GET, url, errorListener);
+ ScaleType scaleType, Config decodeConfig, Response.ErrorListener errorListener) {
+ super(Method.GET, url, errorListener);
setRetryPolicy(
new DefaultRetryPolicy(IMAGE_TIMEOUT_MS, IMAGE_MAX_RETRIES, 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;
@@ -92,14 +106,24 @@ public class ImageRequest extends Request<Bitmap> {
* 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) {
+ int actualSecondary, ScaleType scaleType) {
+
// If no dominant value at all, just return the actual.
- if (maxPrimary == 0 && maxSecondary == 0) {
+ 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;
@@ -112,7 +136,16 @@ public class ImageRequest extends Request<Bitmap> {
double ratio = (double) actualSecondary / (double) actualPrimary;
int resized = maxPrimary;
- if (resized * ratio > maxSecondary) {
+
+ // 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;
@@ -150,9 +183,9 @@ public class ImageRequest extends Request<Bitmap> {
// Then compute the dimensions we would ideally like to decode to.
int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight,
- actualWidth, actualHeight);
+ actualWidth, actualHeight, mScaleType);
int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth,
- actualHeight, actualWidth);
+ actualHeight, actualWidth, mScaleType);
// Decode to the nearest power of two scaling factor.
decodeOptions.inJustDecodeBounds = false;
diff --git a/src/main/java/com/android/volley/toolbox/NetworkImageView.java b/src/main/java/com/android/volley/toolbox/NetworkImageView.java
index 692e988..324dbc0 100644
--- a/src/main/java/com/android/volley/toolbox/NetworkImageView.java
+++ b/src/main/java/com/android/volley/toolbox/NetworkImageView.java
@@ -103,6 +103,7 @@ public class NetworkImageView extends ImageView {
void loadImageIfNecessary(final boolean isInLayoutPass) {
int width = getWidth();
int height = getHeight();
+ ScaleType scaleType = getScaleType();
boolean wrapWidth = false, wrapHeight = false;
if (getLayoutParams() != null) {
@@ -177,7 +178,7 @@ public class NetworkImageView extends ImageView {
setImageResource(mDefaultImageId);
}
}
- }, maxWidth, maxHeight);
+ }, maxWidth, maxHeight, scaleType);
// update the ImageContainer to be the new bitmap container.
mImageContainer = newContainer;