package org.devtcg.five.util;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import org.devtcg.five.Constants;
import org.devtcg.util.IOUtilities;
import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.util.Log;
/**
* Asynchronous bitmap decode helper. Modeled after
* {@link android.content.AsyncQueryHandler}.
*/
public abstract class AsyncBitmapHandler extends Handler
{
private static final String TAG = AsyncBitmapHandler.class.getSimpleName();
private static final boolean DEBUG_MESSAGES = false;
private final WeakReference<ContentResolver> mResolver;
private final WorkerHandler mWorkerThreadHandler;
private static Looper sLooper;
public AsyncBitmapHandler(ContentResolver cr)
{
mResolver = new WeakReference<ContentResolver>(cr);
synchronized (AsyncBitmapHandler.class)
{
if (sLooper == null)
{
HandlerThread thread = new HandlerThread("AsyncBitmapWorker",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
sLooper = thread.getLooper();
}
}
mWorkerThreadHandler = new WorkerHandler(sLooper);
}
public void cancelOperations()
{
/*
* It isn't documented, but removing with token=null actually removes
* all messages.
*/
mWorkerThreadHandler.removeCallbacksAndMessages(null);
}
public void cancelOperation(int token)
{
mWorkerThreadHandler.removeMessages(token);
}
public void startDecode(int token, Object cookie, Uri uri)
{
Message message = mWorkerThreadHandler.obtainMessage(token, WorkerHandler.MSG_DECODE_URI, 0);
WorkerArgs args = new WorkerArgs(this, cookie);
args.uri = uri;
message.obj = args;
message.sendToTarget();
if (DEBUG_MESSAGES)
Log.d(TAG, "Sent request: token=" + token + ", msgType=" + message.arg1);
}
protected abstract void onDecodeComplete(int token, Object cookie, Bitmap result);
@Override
public void handleMessage(Message msg)
{
WorkerArgs args = (WorkerArgs)msg.obj;
int token = msg.what;
int msgType = msg.arg1;
if (DEBUG_MESSAGES)
Log.d(TAG, "Received reply: token=" + token + ", msgType=" + msgType);
switch (msgType)
{
case WorkerHandler.MSG_DECODE_URI:
onDecodeComplete(token, args.cookie, (Bitmap)args.result);
break;
}
}
/**
* Handler attached to the worker thread.
*/
private class WorkerHandler extends Handler
{
private static final int MSG_DECODE_URI = 0;
public WorkerHandler(Looper looper)
{
super(looper);
}
@Override
public void handleMessage(Message msg)
{
ContentResolver resolver = mResolver.get();
WorkerArgs args = (WorkerArgs)msg.obj;
int token = msg.what;
int msgType = msg.arg1;
if (DEBUG_MESSAGES)
Log.d(TAG, "Received request: token=" + token + ", msgType=" + msgType);
switch (msgType)
{
case MSG_DECODE_URI:
if (resolver != null && args.uri != null)
{
try {
args.result = decodeUri(resolver, args.uri);
} catch (OutOfMemoryError e) {
/* Ignore... */
} catch (IOException e) {
if (Constants.DEBUG)
Log.w(TAG, "Unable to decode bitmap at uri=" + args.uri, e);
}
}
break;
}
/*
* Send the response back to the handler that sent the request
* (which is the outer AsyncBitmapHandler).
*/
Message reply = args.handler.obtainMessage(token, msgType, 0);
reply.obj = args;
reply.sendToTarget();
if (DEBUG_MESSAGES)
Log.d(TAG, "Sent reply: token=" + token + ", msgType=" + msgType);
}
}
private static Bitmap decodeUri(ContentResolver resolver, Uri uri) throws IOException
{
InputStream in = resolver.openInputStream(uri);
try {
return BitmapFactory.decodeStream(in);
} finally {
IOUtilities.close(in);
}
}
private static class WorkerArgs
{
public Handler handler;
public Object cookie;
public Uri uri;
public Object result;
public WorkerArgs(Handler handler, Object cookie)
{
this.handler = handler;
this.cookie = cookie;
}
}
}