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.graphics.Bitmap; michael@0: import android.graphics.BitmapFactory; michael@0: import android.net.NetworkInfo; michael@0: import java.io.IOException; michael@0: import java.io.InputStream; michael@0: michael@0: import static com.squareup.picasso.Downloader.Response; michael@0: import static com.squareup.picasso.Picasso.LoadedFrom.DISK; michael@0: import static com.squareup.picasso.Picasso.LoadedFrom.NETWORK; michael@0: michael@0: class NetworkBitmapHunter extends BitmapHunter { michael@0: static final int DEFAULT_RETRY_COUNT = 2; michael@0: private static final int MARKER = 65536; michael@0: michael@0: private final Downloader downloader; michael@0: michael@0: int retryCount; michael@0: michael@0: public NetworkBitmapHunter(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats, michael@0: Action action, Downloader downloader) { michael@0: super(picasso, dispatcher, cache, stats, action); michael@0: this.downloader = downloader; michael@0: this.retryCount = DEFAULT_RETRY_COUNT; michael@0: } michael@0: michael@0: @Override Bitmap decode(Request data) throws IOException { michael@0: boolean loadFromLocalCacheOnly = retryCount == 0; michael@0: michael@0: Response response = downloader.load(data.uri, loadFromLocalCacheOnly); michael@0: if (response == null) { michael@0: return null; michael@0: } michael@0: michael@0: loadedFrom = response.cached ? DISK : NETWORK; michael@0: michael@0: Bitmap result = response.getBitmap(); michael@0: if (result != null) { michael@0: return result; michael@0: } michael@0: michael@0: InputStream is = response.getInputStream(); michael@0: try { michael@0: return decodeStream(is, data); michael@0: } finally { michael@0: Utils.closeQuietly(is); michael@0: } michael@0: } michael@0: michael@0: @Override boolean shouldRetry(boolean airplaneMode, NetworkInfo info) { michael@0: boolean hasRetries = retryCount > 0; michael@0: if (!hasRetries) { michael@0: return false; michael@0: } michael@0: retryCount--; michael@0: return info == null || info.isConnectedOrConnecting(); michael@0: } michael@0: michael@0: private Bitmap decodeStream(InputStream stream, Request data) throws IOException { michael@0: if (stream == null) { michael@0: return null; michael@0: } michael@0: MarkableInputStream markStream = new MarkableInputStream(stream); michael@0: stream = markStream; michael@0: michael@0: long mark = markStream.savePosition(MARKER); michael@0: michael@0: boolean isWebPFile = Utils.isWebPFile(stream); michael@0: markStream.reset(mark); michael@0: // When decode WebP network stream, BitmapFactory throw JNI Exception and make app crash. michael@0: // Decode byte array instead michael@0: if (isWebPFile) { michael@0: byte[] bytes = Utils.toByteArray(stream); michael@0: BitmapFactory.Options options = null; michael@0: if (data.hasSize()) { michael@0: options = new BitmapFactory.Options(); michael@0: options.inJustDecodeBounds = true; michael@0: michael@0: BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); michael@0: calculateInSampleSize(data.targetWidth, data.targetHeight, options); michael@0: } michael@0: return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); michael@0: } else { michael@0: BitmapFactory.Options options = null; michael@0: if (data.hasSize()) { michael@0: options = new BitmapFactory.Options(); michael@0: options.inJustDecodeBounds = true; michael@0: michael@0: BitmapFactory.decodeStream(stream, null, options); michael@0: calculateInSampleSize(data.targetWidth, data.targetHeight, options); michael@0: michael@0: markStream.reset(mark); michael@0: } michael@0: return BitmapFactory.decodeStream(stream, null, options); michael@0: } michael@0: } michael@0: }