| /* |
| * 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: |
| } |
| } |
| } |