package com.koushikdutta.ion; import com.koushikdutta.async.AsyncServer; import com.koushikdutta.async.ByteBufferList; import com.koushikdutta.async.future.Future; import com.koushikdutta.async.future.FutureCallback; import com.koushikdutta.async.http.AsyncHttpRequest; import com.koushikdutta.async.parser.ByteBufferListParser; import com.koushikdutta.async.util.FileCache; import com.koushikdutta.ion.bitmap.BitmapInfo; import com.koushikdutta.ion.bitmap.PostProcess; import com.koushikdutta.ion.bitmap.Transform; import com.koushikdutta.ion.loader.MediaFile; import java.io.File; import java.net.URI; import java.util.ArrayList; class BitmapFetcher implements IonRequestBuilder.LoadRequestCallback { String decodeKey; String bitmapKey; BitmapInfo info; boolean hasTransforms; ArrayList<Transform> transforms; IonRequestBuilder builder; int sampleWidth; int sampleHeight; boolean animateGif; boolean deepZoom; ArrayList<PostProcess> postProcess; public void recomputeDecodeKey() { decodeKey = IonBitmapRequestBuilder.computeDecodeKey(builder, sampleWidth, sampleHeight, animateGif, deepZoom); bitmapKey = IonBitmapRequestBuilder.computeBitmapKey(decodeKey, transforms); } private boolean fastLoad(String uri) { Ion ion = builder.ion; if (deepZoom) { if (uri == null || !uri.startsWith("file:/")) return false; File file = new File(URI.create(uri)); if (!file.exists()) return false; MediaFile.MediaFileType type = MediaFile.getFileType(file.getAbsolutePath()); if (type == null || !MediaFile.isVideoFileType(type.fileType)) { LoadDeepZoom loadDeepZoom = new LoadDeepZoom(ion, decodeKey, animateGif, null); loadDeepZoom.onCompleted(null, new Response<File>(null, ResponseServedFrom.LOADED_FROM_CACHE, null, null, file)); // System.out.println("fastloading deepZoom"); return true; } // fall through to allow some other loader to open this, cause this is a video file } boolean put = !hasTransforms; for (Loader loader: ion.configure().getLoaders()) { Future<BitmapInfo> future = loader.loadBitmap(builder.contextReference.getContext(), ion, decodeKey, uri, sampleWidth, sampleHeight, animateGif); if (future != null) { final BitmapCallback callback = new LoadBitmapBase(ion, decodeKey, put); future.setCallback(new FutureCallback<BitmapInfo>() { @Override public void onCompleted(Exception e, BitmapInfo result) { callback.report(e, result); } }); // System.out.println("fastloading"); return true; } } return false; } public static final int MAX_IMAGEVIEW_LOAD = 5; public static boolean shouldDeferImageView(Ion ion) { if (ion.bitmapsPending.keySet().size() <= MAX_IMAGEVIEW_LOAD) return false; int loadCount = 0; for (String key: ion.bitmapsPending.keySet()) { Object owner = ion.bitmapsPending.tag(key); if (owner instanceof LoadBitmapBase) { loadCount++; if (loadCount > MAX_IMAGEVIEW_LOAD) return true; } } return false; } public DeferredLoadBitmap defer() { DeferredLoadBitmap ret = new DeferredLoadBitmap(builder.ion, decodeKey, this); executeTransforms(builder.ion); return ret; } private void executeTransforms(Ion ion) { // if there's a transform, do it if (!hasTransforms) return; // verify this transform isn't already pending // make sure that the parent download isn't cancelled (empty list) // and also make sure there are waiters for this transformed bitmap if (ion.bitmapsPending.tag(bitmapKey) == null) { ion.bitmapsPending.add(decodeKey, new TransformBitmap(ion, bitmapKey, decodeKey, transforms, postProcess)); } } @Override public boolean loadRequest(AsyncHttpRequest request) { return !fastLoad(request.getUri().toString()); } public void execute() { final Ion ion = builder.ion; // bitmaps that were transformed are put into the FileCache to prevent // subsequent retransformation. See if we can retrieve the bitmap from the disk cache. // See TransformBitmap for where the cache is populated. FileCache fileCache = ion.responseCache.getFileCache(); if (!builder.noCache && fileCache.exists(bitmapKey) && !deepZoom) { BitmapCallback.getBitmapSnapshot(ion, bitmapKey, postProcess); return; } // Perform a download as necessary. if (ion.bitmapsPending.tag(decodeKey) == null && !fastLoad(builder.uri)) { builder.setHandler(null); builder.loadRequestCallback = this; if (!deepZoom) { Future<Response<ByteBufferList>> emitterTransform = builder.execute(new ByteBufferListParser(), new Runnable() { @Override public void run() { AsyncServer.post(Ion.mainHandler, new Runnable() { @Override public void run() { ion.bitmapsPending.remove(decodeKey); } }); } }) .withResponse(); emitterTransform.setCallback(new LoadBitmap(ion, decodeKey, !hasTransforms, sampleWidth, sampleHeight, animateGif)); } else { // System.out.println("downloading file for deepZoom"); File file = fileCache.getTempFile(); Future<Response<File>> emitterTransform = builder.write(file).withResponse(); LoadDeepZoom loadDeepZoom = new LoadDeepZoom(ion, decodeKey, animateGif, fileCache); emitterTransform.setCallback(loadDeepZoom); } } executeTransforms(ion); } }