12bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch/*
22bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch * Copyright (C) 2012 The Android Open Source Project
32bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch *
42bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch * Licensed under the Apache License, Version 2.0 (the "License");
52bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch * you may not use this file except in compliance with the License.
62bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch * You may obtain a copy of the License at
72bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch *
82bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch *      http://www.apache.org/licenses/LICENSE-2.0
92bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch *
102bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch * Unless required by applicable law or agreed to in writing, software
112bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch * distributed under the License is distributed on an "AS IS" BASIS,
122bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch * See the License for the specific language governing permissions and
142bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch * limitations under the License.
152bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch */
162bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
172bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochpackage com.example.android.bitmapfun.util;
182bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
192bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport android.content.Context;
202bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport android.graphics.Bitmap;
212bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport android.net.ConnectivityManager;
222bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport android.net.NetworkInfo;
2303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Kochimport android.os.Build;
242bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport android.util.Log;
252bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport android.widget.Toast;
262bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
272bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport com.example.android.bitmapfun.BuildConfig;
2803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Kochimport com.example.android.bitmapfun.R;
292bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
302bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport java.io.BufferedInputStream;
312bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport java.io.BufferedOutputStream;
322bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport java.io.File;
3303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Kochimport java.io.FileDescriptor;
3403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Kochimport java.io.FileInputStream;
352bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport java.io.IOException;
3603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Kochimport java.io.OutputStream;
372bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport java.net.HttpURLConnection;
382bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochimport java.net.URL;
392bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
402bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch/**
412bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch * A simple subclass of {@link ImageResizer} that fetches and resizes images fetched from a URL.
422bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch */
432bab0137e0af92c374d3efb2ed0e1d894981e015Adam Kochpublic class ImageFetcher extends ImageResizer {
442bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    private static final String TAG = "ImageFetcher";
452bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    private static final int HTTP_CACHE_SIZE = 10 * 1024 * 1024; // 10MB
4603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    private static final String HTTP_CACHE_DIR = "http";
4703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    private static final int IO_BUFFER_SIZE = 8 * 1024;
4803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch
4903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    private DiskLruCache mHttpDiskCache;
5003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    private File mHttpCacheDir;
5103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    private boolean mHttpDiskCacheStarting = true;
5203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    private final Object mHttpDiskCacheLock = new Object();
5303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    private static final int DISK_CACHE_INDEX = 0;
542bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
552bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    /**
562bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * Initialize providing a target image width and height for the processing images.
572bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     *
582bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * @param context
592bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * @param imageWidth
602bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * @param imageHeight
612bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     */
622bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    public ImageFetcher(Context context, int imageWidth, int imageHeight) {
632bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        super(context, imageWidth, imageHeight);
642bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        init(context);
652bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    }
662bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
672bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    /**
682bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * Initialize providing a single target image size (used for both width and height);
692bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     *
702bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * @param context
712bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * @param imageSize
722bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     */
732bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    public ImageFetcher(Context context, int imageSize) {
742bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        super(context, imageSize);
752bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        init(context);
762bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    }
772bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
782bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    private void init(Context context) {
792bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        checkConnection(context);
8003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        mHttpCacheDir = ImageCache.getDiskCacheDir(context, HTTP_CACHE_DIR);
8103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    }
8203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch
8303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    @Override
8403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    protected void initDiskCacheInternal() {
8503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        super.initDiskCacheInternal();
8603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        initHttpDiskCache();
8703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    }
8803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch
8903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    private void initHttpDiskCache() {
9003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        if (!mHttpCacheDir.exists()) {
9103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            mHttpCacheDir.mkdirs();
9203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        }
9303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        synchronized (mHttpDiskCacheLock) {
9403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            if (ImageCache.getUsableSpace(mHttpCacheDir) > HTTP_CACHE_SIZE) {
9503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                try {
9603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    mHttpDiskCache = DiskLruCache.open(mHttpCacheDir, 1, 1, HTTP_CACHE_SIZE);
9703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    if (BuildConfig.DEBUG) {
9803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        Log.d(TAG, "HTTP cache initialized");
9903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    }
10003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                } catch (IOException e) {
10103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    mHttpDiskCache = null;
10203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                }
10303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            }
10403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            mHttpDiskCacheStarting = false;
10503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            mHttpDiskCacheLock.notifyAll();
10603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        }
10703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    }
10803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch
10903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    @Override
11003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    protected void clearCacheInternal() {
11103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        super.clearCacheInternal();
11203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        synchronized (mHttpDiskCacheLock) {
11303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            if (mHttpDiskCache != null && !mHttpDiskCache.isClosed()) {
11403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                try {
11503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    mHttpDiskCache.delete();
11603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    if (BuildConfig.DEBUG) {
11703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        Log.d(TAG, "HTTP cache cleared");
11803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    }
11903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                } catch (IOException e) {
12003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    Log.e(TAG, "clearCacheInternal - " + e);
12103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                }
12203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                mHttpDiskCache = null;
12303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                mHttpDiskCacheStarting = true;
12403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                initHttpDiskCache();
12503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            }
12603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        }
12703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    }
12803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch
12903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    @Override
13003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    protected void flushCacheInternal() {
13103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        super.flushCacheInternal();
13203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        synchronized (mHttpDiskCacheLock) {
13303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            if (mHttpDiskCache != null) {
13403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                try {
13503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    mHttpDiskCache.flush();
13603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    if (BuildConfig.DEBUG) {
13703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        Log.d(TAG, "HTTP cache flushed");
13803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    }
13903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                } catch (IOException e) {
14003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    Log.e(TAG, "flush - " + e);
14103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                }
14203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            }
14303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        }
14403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    }
14503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch
14603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    @Override
14703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    protected void closeCacheInternal() {
14803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        super.closeCacheInternal();
14903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        synchronized (mHttpDiskCacheLock) {
15003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            if (mHttpDiskCache != null) {
15103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                try {
15203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    if (!mHttpDiskCache.isClosed()) {
15303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        mHttpDiskCache.close();
15403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        mHttpDiskCache = null;
15503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        if (BuildConfig.DEBUG) {
15603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                            Log.d(TAG, "HTTP cache closed");
15703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        }
15803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    }
15903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                } catch (IOException e) {
16003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    Log.e(TAG, "closeCacheInternal - " + e);
16103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                }
16203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            }
16303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        }
1642bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    }
1652bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
1662bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    /**
16703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    * Simple network connection check.
16803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    *
16903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    * @param context
17003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    */
1712bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    private void checkConnection(Context context) {
1722bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        final ConnectivityManager cm =
1732bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
1742bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
1752bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        if (networkInfo == null || !networkInfo.isConnectedOrConnecting()) {
17603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            Toast.makeText(context, R.string.no_network_connection_toast, Toast.LENGTH_LONG).show();
1772bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch            Log.e(TAG, "checkConnection - no connection found");
1782bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        }
1792bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    }
1802bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
1812bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    /**
1822bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * The main process method, which will be called by the ImageWorker in the AsyncTask background
1832bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * thread.
1842bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     *
1852bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * @param data The data to load the bitmap, in this case, a regular http URL
1862bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * @return The downloaded and resized bitmap
1872bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     */
1882bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    private Bitmap processBitmap(String data) {
1892bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        if (BuildConfig.DEBUG) {
1902bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch            Log.d(TAG, "processBitmap - " + data);
1912bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        }
1922bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
19303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        final String key = ImageCache.hashKeyForDisk(data);
19403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        FileDescriptor fileDescriptor = null;
19503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        FileInputStream fileInputStream = null;
19603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        DiskLruCache.Snapshot snapshot;
19703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        synchronized (mHttpDiskCacheLock) {
19803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            // Wait for disk cache to initialize
19903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            while (mHttpDiskCacheStarting) {
20003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                try {
20103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    mHttpDiskCacheLock.wait();
20203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                } catch (InterruptedException e) {}
20303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            }
2042bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
20503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            if (mHttpDiskCache != null) {
20603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                try {
20703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    snapshot = mHttpDiskCache.get(key);
20803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    if (snapshot == null) {
20903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        if (BuildConfig.DEBUG) {
21003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                            Log.d(TAG, "processBitmap, not found in http cache, downloading...");
21103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        }
21203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        DiskLruCache.Editor editor = mHttpDiskCache.edit(key);
21303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        if (editor != null) {
21403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                            if (downloadUrlToStream(data,
21503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                                    editor.newOutputStream(DISK_CACHE_INDEX))) {
21603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                                editor.commit();
21703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                            } else {
21803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                                editor.abort();
21903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                            }
22003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        }
22103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        snapshot = mHttpDiskCache.get(key);
22203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    }
22303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    if (snapshot != null) {
22403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        fileInputStream =
22503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                                (FileInputStream) snapshot.getInputStream(DISK_CACHE_INDEX);
22603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        fileDescriptor = fileInputStream.getFD();
22703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    }
22803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                } catch (IOException e) {
22903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    Log.e(TAG, "processBitmap - " + e);
23003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                } catch (IllegalStateException e) {
23103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    Log.e(TAG, "processBitmap - " + e);
23203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                } finally {
23303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    if (fileDescriptor == null && fileInputStream != null) {
23403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        try {
23503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                            fileInputStream.close();
23603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                        } catch (IOException e) {}
23703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    }
23803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                }
23903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            }
2402bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        }
2412bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
24203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        Bitmap bitmap = null;
24303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        if (fileDescriptor != null) {
24403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            bitmap = decodeSampledBitmapFromDescriptor(fileDescriptor, mImageWidth, mImageHeight);
24503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        }
24603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        if (fileInputStream != null) {
24703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            try {
24803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                fileInputStream.close();
24903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            } catch (IOException e) {}
25003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        }
25103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        return bitmap;
2522bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    }
2532bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
2542bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    @Override
2552bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    protected Bitmap processBitmap(Object data) {
2562bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        return processBitmap(String.valueOf(data));
2572bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    }
2582bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
2592bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    /**
26003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch     * Download a bitmap from a URL and write the content to an output stream.
2612bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     *
2622bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     * @param urlString The URL to fetch
26303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch     * @return true if successful, false otherwise
2642bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch     */
26503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    public boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
26603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        disableConnectionReuseIfNecessary();
2672bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        HttpURLConnection urlConnection = null;
2682bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        BufferedOutputStream out = null;
26903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        BufferedInputStream in = null;
2702bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
2712bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        try {
2722bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch            final URL url = new URL(urlString);
2732bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch            urlConnection = (HttpURLConnection) url.openConnection();
27403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            in = new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE);
27503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);
2762bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
2772bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch            int b;
2782bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch            while ((b = in.read()) != -1) {
2792bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch                out.write(b);
2802bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch            }
28103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            return true;
2822bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        } catch (final IOException e) {
2832bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch            Log.e(TAG, "Error in downloadBitmap - " + e);
2842bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        } finally {
2852bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch            if (urlConnection != null) {
2862bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch                urlConnection.disconnect();
2872bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch            }
28803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            try {
28903ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                if (out != null) {
2902bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch                    out.close();
2912bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch                }
29203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                if (in != null) {
29303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                    in.close();
29403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch                }
29503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            } catch (final IOException e) {}
2962bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch        }
29703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        return false;
29803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    }
2992bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch
30003ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    /**
30103ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch     * Workaround for bug pre-Froyo, see here for more info:
30203ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch     * http://android-developers.blogspot.com/2011/09/androids-http-clients.html
30303ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch     */
30403ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch    public static void disableConnectionReuseIfNecessary() {
30503ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        // HTTP connection reuse which was buggy pre-froyo
30603ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
30703ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch            System.setProperty("http.keepAlive", "false");
30803ceb37f79e31626aaac5318b3143a2cfafaea42Adam Koch        }
3092bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch    }
3102bab0137e0af92c374d3efb2ed0e1d894981e015Adam Koch}
311