package com.koushikdutta.ion.loader;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.text.TextUtils;
import android.util.Log;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.FileDataEmitter;
import com.koushikdutta.async.future.Future;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.async.future.SimpleFuture;
import com.koushikdutta.async.http.AsyncHttpRequest;
import com.koushikdutta.async.http.libcore.IoUtils;
import com.koushikdutta.ion.Ion;
import com.koushikdutta.ion.Loader;
import com.koushikdutta.ion.bitmap.BitmapInfo;
import com.koushikdutta.ion.gif.GifAction;
import com.koushikdutta.ion.gif.GifDecoder;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
/**
* Created by koush on 5/22/13.
*/
public class FileLoader extends SimpleLoader {
private static final class FileFuture extends SimpleFuture<DataEmitter> {
}
@Override
public Future<BitmapInfo> loadBitmap(final Ion ion, final String key, final String uri, final int resizeWidth, final int resizeHeight,
final boolean animateGif) {
if (uri == null || !uri.startsWith("file:/"))
return null;
final SimpleFuture<BitmapInfo> ret = new SimpleFuture<BitmapInfo>();
// Log.d("FileLoader", "Loading file bitmap " + uri + " " + resizeWidth + "," + resizeHeight);
Ion.getBitmapLoadExecutorService().execute(new Runnable() {
@Override
public void run() {
if (ret.isCancelled()) {
// Log.d("FileLoader", "Bitmap load cancelled (no longer needed)");
return;
}
try {
File file = new File(URI.create(uri));
BitmapFactory.Options options = ion.getBitmapCache().prepareBitmapOptions(file, resizeWidth, resizeHeight);
if (options == null)
throw new Exception("BitmapFactory.Options failed to load");
Point size = new Point(options.outWidth, options.outHeight);
Bitmap[] bitmaps;
int[] delays;
if (animateGif && TextUtils.equals("image/gif", options.outMimeType)) {
FileInputStream fin = new FileInputStream(file);
GifDecoder decoder = new GifDecoder(fin, new GifAction() {
@Override
public boolean parseOk(boolean parseStatus, int frameIndex) {
return animateGif;
}
});
decoder.run();
IoUtils.closeQuietly(fin);
if (decoder.getFrameCount() == 0)
throw new Exception("failed to load gif");
bitmaps = new Bitmap[decoder.getFrameCount()];
delays = decoder.getDelays();
for (int i = 0; i < decoder.getFrameCount(); i++) {
Bitmap bitmap = decoder.getFrameImage(i);
if (bitmap == null)
throw new Exception("failed to load gif frame");
bitmaps[i] = bitmap;
}
}
else {
Bitmap bitmap = ion.getBitmapCache().loadBitmap(file, options);
if (bitmap == null)
throw new Exception("Bitmap failed to load");
bitmaps = new Bitmap[] { bitmap };
delays = null;
}
BitmapInfo info = new BitmapInfo(key, options.outMimeType, bitmaps, size);
info.delays = delays;
info.loadedFrom = Loader.LoaderEmitter.LOADED_FROM_CACHE;
ret.setComplete(info);
}
catch (OutOfMemoryError e) {
ret.setComplete(new Exception(e), null);
}
catch (Exception e) {
ret.setComplete(e);
}
}
});
return ret;
}
@Override
public Future<InputStream> load(final Ion ion, final AsyncHttpRequest request) {
if (!request.getUri().getScheme().startsWith("file"))
return null;
final SimpleFuture<InputStream> ret = new SimpleFuture<InputStream>();
Ion.getIoExecutorService().execute(new Runnable() {
@Override
public void run() {
try {
InputStream stream = new FileInputStream(new File(request.getUri()));
ret.setComplete(stream);
} catch (Exception e) {
ret.setComplete(e);
}
}
});
return ret;
}
@Override
public Future<DataEmitter> load(final Ion ion, final AsyncHttpRequest request, final FutureCallback<LoaderEmitter> callback) {
if (!request.getUri().getScheme().startsWith("file"))
return null;
final FileFuture ret = new FileFuture();
ion.getHttpClient().getServer().post(new Runnable() {
@Override
public void run() {
File file = new File(request.getUri());
FileDataEmitter emitter = new FileDataEmitter(ion.getHttpClient().getServer(), file);
ret.setComplete(emitter);
callback.onCompleted(null, new LoaderEmitter(emitter, (int)file.length(), LoaderEmitter.LOADED_FROM_CACHE, null, request));
}
});
return ret;
}
}