package gws.grottworkshop.gwsholmeswatson.view;
import gws.grottworkshop.gwsholmeswatson.GWSApplication;
import gws.grottworkshop.gwsholmeswatson.cache.ImageCache;
import java.io.BufferedInputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Message;
import android.os.SystemClock;
// TODO: Auto-generated Javadoc
/**
* Modified from paginatedgallery touse logback as logger
* and a modified imagecache.
*
* @author fredgrott
*
*/
public class RemoteImageLoaderJob implements Runnable {
/** The gwslog. */
private Logger GWSLOG = LoggerFactory.getLogger(RemoteImageLoaderJob.class);
/** The Constant DEFAULT_RETRY_HANDLER_SLEEP_TIME. */
private static final int DEFAULT_RETRY_HANDLER_SLEEP_TIME = 1000;
/** The image url. */
private String imageUrl;
/** The handler. */
private RemoteImageLoaderHandler handler;
/** The image cache. */
private ImageCache imageCache = GWSApplication.getImageCache();
/** The default buffer size. */
private int numRetries, defaultBufferSize;
/**
* Instantiates a new remote image loader job.
*
* @param imageUrl the image url
* @param handler the handler
* @param imageCache the image cache
* @param numRetries the num retries
* @param defaultBufferSize the default buffer size
*/
public RemoteImageLoaderJob(String imageUrl, RemoteImageLoaderHandler handler, ImageCache imageCache,
int numRetries, int defaultBufferSize) {
this.imageUrl = imageUrl;
this.handler = handler;
this.imageCache = imageCache;
this.numRetries = numRetries;
}
/**
* The job method run on a worker thread. It will first query the image cache, and on a miss,
* download the image from the Web.
*/
@Override
public void run() {
Bitmap bitmap = null;
if (imageCache != null) {
// at this point we know the image is not in memory, but it could be cached to SD card
bitmap = imageCache.getBitmap(imageUrl);
}
if (bitmap == null) {
bitmap = downloadImage();
}
notifyImageLoaded(imageUrl, bitmap);
}
// TODO: we could probably improve performance by re-using connections instead of closing them
// after each and every download
/**
* Download image.
*
* @return the bitmap
*/
protected Bitmap downloadImage() {
int timesTried = 1;
while (timesTried <= numRetries) {
try {
byte[] imageData = retrieveImageData();
if (imageData == null) {
break;
}
if (imageCache != null) {
imageCache.put(imageUrl, imageData);
}
return BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
} catch (Throwable e) {
GWSLOG.warn( "download for " + imageUrl + " failed (attempt " + timesTried + ")");
e.printStackTrace();
SystemClock.sleep(DEFAULT_RETRY_HANDLER_SLEEP_TIME);
timesTried++;
}
}
return null;
}
/**
* Retrieve image data.
*
* @return the byte[]
* @throws IOException Signals that an I/O exception has occurred.
*/
protected byte[] retrieveImageData() throws java.io.IOException {
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// connection.setRequestProperty("Authorization", "Basic "+ "bm9xc3RvcmU6dHJpYWw=");
// determine the image size and allocate a buffer
int fileSize = connection.getContentLength();
if (fileSize <= 0) {
fileSize = defaultBufferSize;
GWSLOG.warn("Server did not set a Content-Length header, will default to buffer size of "
+ defaultBufferSize + " bytes");
}
byte[] imageData = new byte[fileSize];
// download the file
GWSLOG.warn( "fetching image " + imageUrl + " (" + fileSize + ")");
BufferedInputStream istream = new BufferedInputStream(connection.getInputStream());
int bytesRead = 0;
int offset = 0;
while (bytesRead != -1 && offset < fileSize) {
bytesRead = istream.read(imageData, offset, fileSize - offset);
offset += bytesRead;
}
// clean up
istream.close();
connection.disconnect();
return imageData;
}
/**
* Notify image loaded.
*
* @param url the url
* @param bitmap the bitmap
*/
protected void notifyImageLoaded(String url, Bitmap bitmap) {
Message message = new Message();
message.what = RemoteImageLoaderHandler.HANDLER_MESSAGE_ID;
Bundle data = new Bundle();
data.putString(RemoteImageLoaderHandler.IMAGE_URL_EXTRA, url);
Bitmap image = bitmap;
data.putParcelable(RemoteImageLoaderHandler.BITMAP_EXTRA, image);
message.setData(data);
handler.sendMessage(message);
}
}