michael@0: /* michael@0: * Copyright (C) 2013 Square, Inc. michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: package com.squareup.picasso; michael@0: michael@0: import android.content.Context; michael@0: import android.net.Uri; michael@0: import android.net.http.HttpResponseCache; michael@0: import android.os.Build; michael@0: import java.io.File; michael@0: import java.io.IOException; michael@0: import java.net.HttpURLConnection; michael@0: import java.net.URL; michael@0: michael@0: import static com.squareup.picasso.Utils.parseResponseSourceHeader; michael@0: michael@0: /** michael@0: * A {@link Downloader} which uses {@link HttpURLConnection} to download images. A disk cache of 2% michael@0: * of the total available space will be used (capped at 50MB) will automatically be installed in the michael@0: * application's cache directory, when available. michael@0: */ michael@0: public class UrlConnectionDownloader implements Downloader { michael@0: static final String RESPONSE_SOURCE = "X-Android-Response-Source"; michael@0: michael@0: private static final Object lock = new Object(); michael@0: static volatile Object cache; michael@0: michael@0: private final Context context; michael@0: michael@0: public UrlConnectionDownloader(Context context) { michael@0: this.context = context.getApplicationContext(); michael@0: } michael@0: michael@0: protected HttpURLConnection openConnection(Uri path) throws IOException { michael@0: HttpURLConnection connection = (HttpURLConnection) new URL(path.toString()).openConnection(); michael@0: connection.setConnectTimeout(Utils.DEFAULT_CONNECT_TIMEOUT); michael@0: connection.setReadTimeout(Utils.DEFAULT_READ_TIMEOUT); michael@0: return connection; michael@0: } michael@0: michael@0: @Override public Response load(Uri uri, boolean localCacheOnly) throws IOException { michael@0: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { michael@0: installCacheIfNeeded(context); michael@0: } michael@0: michael@0: HttpURLConnection connection = openConnection(uri); michael@0: connection.setUseCaches(true); michael@0: if (localCacheOnly) { michael@0: connection.setRequestProperty("Cache-Control", "only-if-cached,max-age=" + Integer.MAX_VALUE); michael@0: } michael@0: michael@0: int responseCode = connection.getResponseCode(); michael@0: if (responseCode >= 300) { michael@0: connection.disconnect(); michael@0: throw new ResponseException(responseCode + " " + connection.getResponseMessage()); michael@0: } michael@0: michael@0: boolean fromCache = parseResponseSourceHeader(connection.getHeaderField(RESPONSE_SOURCE)); michael@0: michael@0: return new Response(connection.getInputStream(), fromCache); michael@0: } michael@0: michael@0: private static void installCacheIfNeeded(Context context) { michael@0: // DCL + volatile should be safe after Java 5. michael@0: if (cache == null) { michael@0: try { michael@0: synchronized (lock) { michael@0: if (cache == null) { michael@0: cache = ResponseCacheIcs.install(context); michael@0: } michael@0: } michael@0: } catch (IOException ignored) { michael@0: } michael@0: } michael@0: } michael@0: michael@0: private static class ResponseCacheIcs { michael@0: static Object install(Context context) throws IOException { michael@0: File cacheDir = Utils.createDefaultCacheDir(context); michael@0: HttpResponseCache cache = HttpResponseCache.getInstalled(); michael@0: if (cache == null) { michael@0: long maxSize = Utils.calculateDiskCacheSize(cacheDir); michael@0: cache = HttpResponseCache.install(cacheDir, maxSize); michael@0: } michael@0: return cache; michael@0: } michael@0: } michael@0: }