• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.calendar;
18 
19 import android.content.Context;
20 import android.graphics.drawable.Drawable;
21 import android.net.Uri;
22 import android.os.Handler;
23 import android.os.HandlerThread;
24 import android.os.Looper;
25 import android.os.Message;
26 import android.provider.ContactsContract.Contacts;
27 import android.util.Log;
28 import android.view.View;
29 import android.widget.ImageView;
30 
31 import java.io.InputStream;
32 
33 /**
34  * Helper class for async access of images.
35  */
36 public class ContactsAsyncHelper extends Handler {
37 
38     private static final boolean DBG = false;
39     private static final String LOG_TAG = "ContactsAsyncHelper";
40 
41     /**
42      * Interface for a WorkerHandler result return.
43      */
44     public interface OnImageLoadCompleteListener {
45         /**
46          * Called when the image load is complete.
47          *
48          * @param imagePresent true if an image was found
49          */
onImageLoadComplete(int token, Object cookie, ImageView iView, boolean imagePresent)50         public void onImageLoadComplete(int token, Object cookie, ImageView iView,
51                 boolean imagePresent);
52     }
53 
54     // constants
55     private static final int EVENT_LOAD_IMAGE = 1;
56     private static final int DEFAULT_TOKEN = -1;
57 
58     // static objects
59     private static Handler sThreadHandler;
60     private static ContactsAsyncHelper sInstance;
61 
62     static {
63         sInstance = new ContactsAsyncHelper();
64     }
65 
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;
72     }
73 
74     /**
75      * Thread worker class that handles the task of opening the stream and loading
76      * the images.
77      */
78     private class WorkerHandler extends Handler {
WorkerHandler(Looper looper)79         public WorkerHandler(Looper looper) {
80             super(looper);
81         }
82 
83         @Override
handleMessage(Message msg)84         public void handleMessage(Message msg) {
85             WorkerArgs args = (WorkerArgs) msg.obj;
86 
87             switch (msg.arg1) {
88                 case EVENT_LOAD_IMAGE:
89                     InputStream inputStream = null;
90                     try {
91                         inputStream = Contacts.openContactPhotoInputStream(
92                                 args.context.getContentResolver(), args.uri);
93                     } catch (Exception e) {
94                         Log.e(LOG_TAG, "Error opening photo input stream", e);
95                     }
96 
97                     if (inputStream != null) {
98                         args.result = Drawable.createFromStream(inputStream, args.uri.toString());
99 
100                         if (DBG) Log.d(LOG_TAG, "Loading image: " + msg.arg1 +
101                                 " token: " + msg.what + " image URI: " + args.uri);
102                     } else {
103                         args.result = null;
104                         if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
105                                 " token: " + msg.what + " image URI: " + args.uri +
106                                 ", using default image.");
107                     }
108                     break;
109                 default:
110             }
111 
112             // send the reply to the enclosing class.
113             Message reply = ContactsAsyncHelper.this.obtainMessage(msg.what);
114             reply.arg1 = msg.arg1;
115             reply.obj = msg.obj;
116             reply.sendToTarget();
117         }
118     }
119 
120     /**
121      * Private constructor for static class
122      */
ContactsAsyncHelper()123     private ContactsAsyncHelper() {
124         HandlerThread thread = new HandlerThread("ContactsAsyncWorker");
125         thread.start();
126         sThreadHandler = new WorkerHandler(thread.getLooper());
127     }
128 
129     /**
130      * Start an image load, attach the result to the specified CallerInfo object.
131      * Note, when the query is started, we make the ImageView INVISIBLE if the
132      * placeholderImageResource value is -1.  When we're given a valid (!= -1)
133      * placeholderImageResource value, we make sure the image is visible.
134      */
updateImageViewWithContactPhotoAsync(Context context, ImageView imageView, Uri person, int placeholderImageResource)135     public static final void updateImageViewWithContactPhotoAsync(Context context,
136             ImageView imageView, Uri person, int placeholderImageResource) {
137 
138         // in case the source caller info is null, the URI will be null as well.
139         // just update using the placeholder image in this case.
140         if (person == null) {
141             if (DBG) Log.d(LOG_TAG, "target image is null, just display placeholder.");
142             imageView.setVisibility(View.VISIBLE);
143             imageView.setImageResource(placeholderImageResource);
144             return;
145         }
146 
147         // Added additional Cookie field in the callee to handle arguments
148         // sent to the callback function.
149 
150         // setup arguments
151         WorkerArgs args = new WorkerArgs();
152         args.context = context;
153         args.view = imageView;
154         args.uri = person;
155         args.defaultResource = placeholderImageResource;
156 
157         // setup message arguments
158         Message msg = sThreadHandler.obtainMessage(DEFAULT_TOKEN);
159         msg.arg1 = EVENT_LOAD_IMAGE;
160         msg.obj = args;
161 
162         if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri +
163                 ", displaying default image for now.");
164 
165         // set the default image first, when the query is complete, we will
166         // replace the image with the correct one.
167         if (placeholderImageResource != -1) {
168             imageView.setVisibility(View.VISIBLE);
169             imageView.setImageResource(placeholderImageResource);
170         } else {
171             imageView.setVisibility(View.INVISIBLE);
172         }
173 
174         // notify the thread to begin working
175         sThreadHandler.sendMessage(msg);
176     }
177 
178     /**
179      * Called when loading is done.
180      */
181     @Override
handleMessage(Message msg)182     public void handleMessage(Message msg) {
183         WorkerArgs args = (WorkerArgs) msg.obj;
184         switch (msg.arg1) {
185             case EVENT_LOAD_IMAGE:
186                 boolean imagePresent = false;
187 
188                 // if the image has been loaded then display it, otherwise set default.
189                 // in either case, make sure the image is visible.
190                 if (args.result != null) {
191                     args.view.setVisibility(View.VISIBLE);
192                     args.view.setImageDrawable((Drawable) args.result);
193                     imagePresent = true;
194                 } else if (args.defaultResource != -1) {
195                     args.view.setVisibility(View.VISIBLE);
196                     args.view.setImageResource(args.defaultResource);
197                 }
198                 break;
199             default:
200         }
201     }
202 }
203