blob: b7e01dbacb96c3e2980f2369b087d728fa122c87 [file] [log] [blame]
Michael Chan037c0692010-02-09 13:32:22 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.calendar;
18
Erikd845fbe2010-08-12 11:20:01 -070019import com.android.calendar.event.EditEventHelper.AttendeeItem;
20
Michael Chan037c0692010-02-09 13:32:22 -080021import android.content.Context;
22import android.graphics.drawable.Drawable;
23import android.net.Uri;
24import android.os.Handler;
25import android.os.HandlerThread;
26import android.os.Looper;
27import android.os.Message;
28import android.provider.ContactsContract.Contacts;
29import android.util.Log;
30import android.view.View;
31import android.widget.ImageView;
32
33import java.io.InputStream;
34
35/**
36 * Helper class for async access of images.
37 */
38public class ContactsAsyncHelper extends Handler {
39
40 private static final boolean DBG = false;
41 private static final String LOG_TAG = "ContactsAsyncHelper";
42
Erika7694ee2010-12-07 15:46:18 -080043 private static ContactsAsyncHelper mInstance = null;
44
Michael Chan037c0692010-02-09 13:32:22 -080045 /**
46 * Interface for a WorkerHandler result return.
47 */
48 public interface OnImageLoadCompleteListener {
49 /**
50 * Called when the image load is complete.
51 *
52 * @param imagePresent true if an image was found
53 */
54 public void onImageLoadComplete(int token, Object cookie, ImageView iView,
55 boolean imagePresent);
56 }
57
58 // constants
59 private static final int EVENT_LOAD_IMAGE = 1;
Erikd845fbe2010-08-12 11:20:01 -070060 private static final int EVENT_LOAD_DRAWABLE = 2;
Michael Chan037c0692010-02-09 13:32:22 -080061 private static final int DEFAULT_TOKEN = -1;
62
63 // static objects
64 private static Handler sThreadHandler;
Michael Chan037c0692010-02-09 13:32:22 -080065
66 private static final class WorkerArgs {
67 public Context context;
68 public ImageView view;
69 public Uri uri;
70 public int defaultResource;
71 public Object result;
Erikd845fbe2010-08-12 11:20:01 -070072 public AttendeeItem item;
73 public Runnable callback;
Michael Chan037c0692010-02-09 13:32:22 -080074 }
75
76 /**
77 * Thread worker class that handles the task of opening the stream and loading
78 * the images.
79 */
80 private class WorkerHandler extends Handler {
81 public WorkerHandler(Looper looper) {
82 super(looper);
83 }
84
85 @Override
86 public void handleMessage(Message msg) {
87 WorkerArgs args = (WorkerArgs) msg.obj;
88
89 switch (msg.arg1) {
Erikd845fbe2010-08-12 11:20:01 -070090 case EVENT_LOAD_DRAWABLE:
Michael Chan037c0692010-02-09 13:32:22 -080091 case EVENT_LOAD_IMAGE:
92 InputStream inputStream = null;
93 try {
94 inputStream = Contacts.openContactPhotoInputStream(
95 args.context.getContentResolver(), args.uri);
96 } catch (Exception e) {
97 Log.e(LOG_TAG, "Error opening photo input stream", e);
98 }
99
100 if (inputStream != null) {
101 args.result = Drawable.createFromStream(inputStream, args.uri.toString());
102
103 if (DBG) Log.d(LOG_TAG, "Loading image: " + msg.arg1 +
104 " token: " + msg.what + " image URI: " + args.uri);
105 } else {
106 args.result = null;
107 if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
108 " token: " + msg.what + " image URI: " + args.uri +
109 ", using default image.");
110 }
111 break;
112 default:
113 }
114
115 // send the reply to the enclosing class.
116 Message reply = ContactsAsyncHelper.this.obtainMessage(msg.what);
117 reply.arg1 = msg.arg1;
118 reply.obj = msg.obj;
119 reply.sendToTarget();
120 }
121 }
122
123 /**
124 * Private constructor for static class
125 */
126 private ContactsAsyncHelper() {
127 HandlerThread thread = new HandlerThread("ContactsAsyncWorker");
128 thread.start();
129 sThreadHandler = new WorkerHandler(thread.getLooper());
130 }
131
132 /**
133 * Start an image load, attach the result to the specified CallerInfo object.
134 * Note, when the query is started, we make the ImageView INVISIBLE if the
135 * placeholderImageResource value is -1. When we're given a valid (!= -1)
136 * placeholderImageResource value, we make sure the image is visible.
137 */
138 public static final void updateImageViewWithContactPhotoAsync(Context context,
Daniel Lehmann8fa31112012-02-07 14:37:19 -0800139 ImageView imageView, Uri contact, int placeholderImageResource) {
Michael Chan037c0692010-02-09 13:32:22 -0800140
141 // in case the source caller info is null, the URI will be null as well.
142 // just update using the placeholder image in this case.
Daniel Lehmann8fa31112012-02-07 14:37:19 -0800143 if (contact == null) {
Michael Chan037c0692010-02-09 13:32:22 -0800144 if (DBG) Log.d(LOG_TAG, "target image is null, just display placeholder.");
145 imageView.setVisibility(View.VISIBLE);
146 imageView.setImageResource(placeholderImageResource);
147 return;
148 }
149
150 // Added additional Cookie field in the callee to handle arguments
151 // sent to the callback function.
152
153 // setup arguments
154 WorkerArgs args = new WorkerArgs();
155 args.context = context;
156 args.view = imageView;
Daniel Lehmann8fa31112012-02-07 14:37:19 -0800157 args.uri = contact;
Michael Chan037c0692010-02-09 13:32:22 -0800158 args.defaultResource = placeholderImageResource;
159
Erika7694ee2010-12-07 15:46:18 -0800160 if (mInstance == null) {
161 mInstance = new ContactsAsyncHelper();
162 }
Michael Chan037c0692010-02-09 13:32:22 -0800163 // setup message arguments
164 Message msg = sThreadHandler.obtainMessage(DEFAULT_TOKEN);
165 msg.arg1 = EVENT_LOAD_IMAGE;
166 msg.obj = args;
167
168 if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri +
169 ", displaying default image for now.");
170
171 // set the default image first, when the query is complete, we will
172 // replace the image with the correct one.
173 if (placeholderImageResource != -1) {
174 imageView.setVisibility(View.VISIBLE);
175 imageView.setImageResource(placeholderImageResource);
176 } else {
177 imageView.setVisibility(View.INVISIBLE);
178 }
179
180 // notify the thread to begin working
181 sThreadHandler.sendMessage(msg);
182 }
183
184 /**
Erikd845fbe2010-08-12 11:20:01 -0700185 * Start an image load, attach the result to the specified CallerInfo object.
186 * Note, when the query is started, we make the ImageView INVISIBLE if the
187 * placeholderImageResource value is -1. When we're given a valid (!= -1)
188 * placeholderImageResource value, we make sure the image is visible.
189 */
190 public static final void retrieveContactPhotoAsync(Context context,
Daniel Lehmann8fa31112012-02-07 14:37:19 -0800191 AttendeeItem item, Runnable run, Uri photoUri) {
Erikd845fbe2010-08-12 11:20:01 -0700192
193 // in case the source caller info is null, the URI will be null as well.
194 // just return as there's nothing to do.
Daniel Lehmann8fa31112012-02-07 14:37:19 -0800195 if (photoUri == null) {
Erikd845fbe2010-08-12 11:20:01 -0700196 return;
197 }
198
199 // Added additional Cookie field in the callee to handle arguments
200 // sent to the callback function.
201
202 // setup arguments
203 WorkerArgs args = new WorkerArgs();
204 args.context = context;
205 args.item = item;
Daniel Lehmann8fa31112012-02-07 14:37:19 -0800206 args.uri = photoUri;
Erikd845fbe2010-08-12 11:20:01 -0700207 args.callback = run;
208
Erika7694ee2010-12-07 15:46:18 -0800209 if (mInstance == null) {
210 mInstance = new ContactsAsyncHelper();
211 }
Erikd845fbe2010-08-12 11:20:01 -0700212 // setup message arguments
213 Message msg = sThreadHandler.obtainMessage(DEFAULT_TOKEN);
214 msg.arg1 = EVENT_LOAD_DRAWABLE;
215 msg.obj = args;
216
217 if (DBG) Log.d(LOG_TAG, "Begin loading drawable: " + args.uri);
218
219
220 // notify the thread to begin working
221 sThreadHandler.sendMessage(msg);
222 }
223
224 /**
Michael Chan037c0692010-02-09 13:32:22 -0800225 * Called when loading is done.
226 */
227 @Override
228 public void handleMessage(Message msg) {
229 WorkerArgs args = (WorkerArgs) msg.obj;
230 switch (msg.arg1) {
231 case EVENT_LOAD_IMAGE:
Michael Chan037c0692010-02-09 13:32:22 -0800232 // if the image has been loaded then display it, otherwise set default.
233 // in either case, make sure the image is visible.
234 if (args.result != null) {
235 args.view.setVisibility(View.VISIBLE);
236 args.view.setImageDrawable((Drawable) args.result);
Michael Chan037c0692010-02-09 13:32:22 -0800237 } else if (args.defaultResource != -1) {
238 args.view.setVisibility(View.VISIBLE);
239 args.view.setImageResource(args.defaultResource);
240 }
241 break;
Erikd845fbe2010-08-12 11:20:01 -0700242 case EVENT_LOAD_DRAWABLE:
243 if (args.result != null) {
244 args.item.mBadge = (Drawable) args.result;
245 if (args.callback != null) {
246 args.callback.run();
247 }
248 }
249 break;
Michael Chan037c0692010-02-09 13:32:22 -0800250 default:
251 }
252 }
253}