blob: b7e01dbacb96c3e2980f2369b087d728fa122c87 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.calendar;
import com.android.calendar.event.EditEventHelper.AttendeeItem;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.provider.ContactsContract.Contacts;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import java.io.InputStream;
/**
* Helper class for async access of images.
*/
public class ContactsAsyncHelper extends Handler {
private static final boolean DBG = false;
private static final String LOG_TAG = "ContactsAsyncHelper";
private static ContactsAsyncHelper mInstance = null;
/**
* Interface for a WorkerHandler result return.
*/
public interface OnImageLoadCompleteListener {
/**
* Called when the image load is complete.
*
* @param imagePresent true if an image was found
*/
public void onImageLoadComplete(int token, Object cookie, ImageView iView,
boolean imagePresent);
}
// constants
private static final int EVENT_LOAD_IMAGE = 1;
private static final int EVENT_LOAD_DRAWABLE = 2;
private static final int DEFAULT_TOKEN = -1;
// static objects
private static Handler sThreadHandler;
private static final class WorkerArgs {
public Context context;
public ImageView view;
public Uri uri;
public int defaultResource;
public Object result;
public AttendeeItem item;
public Runnable callback;
}
/**
* Thread worker class that handles the task of opening the stream and loading
* the images.
*/
private class WorkerHandler extends Handler {
public WorkerHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
WorkerArgs args = (WorkerArgs) msg.obj;
switch (msg.arg1) {
case EVENT_LOAD_DRAWABLE:
case EVENT_LOAD_IMAGE:
InputStream inputStream = null;
try {
inputStream = Contacts.openContactPhotoInputStream(
args.context.getContentResolver(), args.uri);
} catch (Exception e) {
Log.e(LOG_TAG, "Error opening photo input stream", e);
}
if (inputStream != null) {
args.result = Drawable.createFromStream(inputStream, args.uri.toString());
if (DBG) Log.d(LOG_TAG, "Loading image: " + msg.arg1 +
" token: " + msg.what + " image URI: " + args.uri);
} else {
args.result = null;
if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
" token: " + msg.what + " image URI: " + args.uri +
", using default image.");
}
break;
default:
}
// send the reply to the enclosing class.
Message reply = ContactsAsyncHelper.this.obtainMessage(msg.what);
reply.arg1 = msg.arg1;
reply.obj = msg.obj;
reply.sendToTarget();
}
}
/**
* Private constructor for static class
*/
private ContactsAsyncHelper() {
HandlerThread thread = new HandlerThread("ContactsAsyncWorker");
thread.start();
sThreadHandler = new WorkerHandler(thread.getLooper());
}
/**
* Start an image load, attach the result to the specified CallerInfo object.
* Note, when the query is started, we make the ImageView INVISIBLE if the
* placeholderImageResource value is -1. When we're given a valid (!= -1)
* placeholderImageResource value, we make sure the image is visible.
*/
public static final void updateImageViewWithContactPhotoAsync(Context context,
ImageView imageView, Uri contact, int placeholderImageResource) {
// in case the source caller info is null, the URI will be null as well.
// just update using the placeholder image in this case.
if (contact == null) {
if (DBG) Log.d(LOG_TAG, "target image is null, just display placeholder.");
imageView.setVisibility(View.VISIBLE);
imageView.setImageResource(placeholderImageResource);
return;
}
// Added additional Cookie field in the callee to handle arguments
// sent to the callback function.
// setup arguments
WorkerArgs args = new WorkerArgs();
args.context = context;
args.view = imageView;
args.uri = contact;
args.defaultResource = placeholderImageResource;
if (mInstance == null) {
mInstance = new ContactsAsyncHelper();
}
// setup message arguments
Message msg = sThreadHandler.obtainMessage(DEFAULT_TOKEN);
msg.arg1 = EVENT_LOAD_IMAGE;
msg.obj = args;
if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri +
", displaying default image for now.");
// set the default image first, when the query is complete, we will
// replace the image with the correct one.
if (placeholderImageResource != -1) {
imageView.setVisibility(View.VISIBLE);
imageView.setImageResource(placeholderImageResource);
} else {
imageView.setVisibility(View.INVISIBLE);
}
// notify the thread to begin working
sThreadHandler.sendMessage(msg);
}
/**
* Start an image load, attach the result to the specified CallerInfo object.
* Note, when the query is started, we make the ImageView INVISIBLE if the
* placeholderImageResource value is -1. When we're given a valid (!= -1)
* placeholderImageResource value, we make sure the image is visible.
*/
public static final void retrieveContactPhotoAsync(Context context,
AttendeeItem item, Runnable run, Uri photoUri) {
// in case the source caller info is null, the URI will be null as well.
// just return as there's nothing to do.
if (photoUri == null) {
return;
}
// Added additional Cookie field in the callee to handle arguments
// sent to the callback function.
// setup arguments
WorkerArgs args = new WorkerArgs();
args.context = context;
args.item = item;
args.uri = photoUri;
args.callback = run;
if (mInstance == null) {
mInstance = new ContactsAsyncHelper();
}
// setup message arguments
Message msg = sThreadHandler.obtainMessage(DEFAULT_TOKEN);
msg.arg1 = EVENT_LOAD_DRAWABLE;
msg.obj = args;
if (DBG) Log.d(LOG_TAG, "Begin loading drawable: " + args.uri);
// notify the thread to begin working
sThreadHandler.sendMessage(msg);
}
/**
* Called when loading is done.
*/
@Override
public void handleMessage(Message msg) {
WorkerArgs args = (WorkerArgs) msg.obj;
switch (msg.arg1) {
case EVENT_LOAD_IMAGE:
// if the image has been loaded then display it, otherwise set default.
// in either case, make sure the image is visible.
if (args.result != null) {
args.view.setVisibility(View.VISIBLE);
args.view.setImageDrawable((Drawable) args.result);
} else if (args.defaultResource != -1) {
args.view.setVisibility(View.VISIBLE);
args.view.setImageResource(args.defaultResource);
}
break;
case EVENT_LOAD_DRAWABLE:
if (args.result != null) {
args.item.mBadge = (Drawable) args.result;
if (args.callback != null) {
args.callback.run();
}
}
break;
default:
}
}
}