blob: b9a7c803c39fe1c58276c98fb753f20442e4b422 [file] [log] [blame]
Mindy Pereira84dd9a82011-06-01 11:13:08 -07001/*
2 * Copyright (C) 2011 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 */
Mindy Pereira97d77682011-06-01 10:48:55 -070016
17package com.android.ex.chips;
18
mindyp16923ee2012-12-10 11:58:29 -080019import android.accounts.Account;
20import android.content.ContentResolver;
Mindy Pereira97d77682011-06-01 10:48:55 -070021import android.content.Context;
22import android.database.Cursor;
Makoto Onukia5d37c82012-05-03 13:40:45 -070023import android.database.MatrixCursor;
mindyp16923ee2012-12-10 11:58:29 -080024import android.net.Uri;
25import android.provider.ContactsContract;
Scott Kennedyef3f76c2013-02-25 10:48:25 -080026import android.text.TextUtils;
Mindy Pereira18529312011-06-28 11:00:52 -070027import android.text.util.Rfc822Token;
28import android.text.util.Rfc822Tokenizer;
Mindy Pereira18987c42011-07-11 11:26:46 -070029import android.util.Log;
Mindy Pereira97d77682011-06-01 10:48:55 -070030import android.view.LayoutInflater;
31import android.view.View;
32import android.view.ViewGroup;
33import android.widget.CursorAdapter;
Mindy Pereira67ad4892011-06-02 12:21:22 -070034import android.widget.ImageView;
Mindy Pereira97d77682011-06-01 10:48:55 -070035import android.widget.TextView;
36
mindyp16923ee2012-12-10 11:58:29 -080037import com.android.ex.chips.BaseRecipientAdapter.DirectoryListQuery;
38import com.android.ex.chips.BaseRecipientAdapter.DirectorySearchParams;
Tom Taylor80f4abf2012-04-06 13:37:20 -070039import com.android.ex.chips.Queries.Query;
Makoto Onukia5d37c82012-05-03 13:40:45 -070040
Mindy Pereira03cfe3e2012-05-24 13:21:59 -070041import java.util.ArrayList;
Mindy Pereira18529312011-06-28 11:00:52 -070042import java.util.HashMap;
Makoto Onukia5d37c82012-05-03 13:40:45 -070043import java.util.HashSet;
mindyp16923ee2012-12-10 11:58:29 -080044import java.util.List;
Scott Kennedy94fa3012013-02-15 18:22:05 -080045import java.util.Map;
46import java.util.Set;
Mindy Pereira18529312011-06-28 11:00:52 -070047
Tom Taylor80f4abf2012-04-06 13:37:20 -070048/**
49 * RecipientAlternatesAdapter backs the RecipientEditTextView for managing contacts
50 * queried by email or by phone number.
51 */
Mindy Pereira97d77682011-06-01 10:48:55 -070052public class RecipientAlternatesAdapter extends CursorAdapter {
Mindy Pereira18529312011-06-28 11:00:52 -070053 static final int MAX_LOOKUPS = 50;
Mindy Pereira97d77682011-06-01 10:48:55 -070054 private final LayoutInflater mLayoutInflater;
55
Mindy Pereira97d77682011-06-01 10:48:55 -070056 private final long mCurrentId;
57
Mindy Pereira007a76b2011-06-14 11:39:36 -070058 private int mCheckedItemPosition = -1;
59
Mindy Pereira50863912011-06-16 18:54:10 -070060 private OnCheckedItemChangedListener mCheckedItemChangedListener;
61
Mindy Pereira18987c42011-07-11 11:26:46 -070062 private static final String TAG = "RecipAlternates";
63
Tom Taylor80f4abf2012-04-06 13:37:20 -070064 public static final int QUERY_TYPE_EMAIL = 0;
65 public static final int QUERY_TYPE_PHONE = 1;
66 private Query mQuery;
67
mindyp16923ee2012-12-10 11:58:29 -080068 public interface RecipientMatchCallback {
Scott Kennedy94fa3012013-02-15 18:22:05 -080069 public void matchesFound(Map<String, RecipientEntry> results);
70 /**
71 * Called with all addresses that could not be resolved to valid recipients.
72 */
Scott Kennedyf7e202d2013-03-06 21:38:10 -080073 public void matchesNotFound(Set<String> unfoundAddresses);
mindyp16923ee2012-12-10 11:58:29 -080074 }
75
Alon Albert76f1f2d2013-07-14 15:32:49 +030076 public static void getMatchingRecipients(Context context, BaseRecipientAdapter adapter,
77 ArrayList<String> inAddresses, Account account, RecipientMatchCallback callback) {
78 getMatchingRecipients(context, adapter, inAddresses, QUERY_TYPE_EMAIL, account, callback);
Tom Taylor80f4abf2012-04-06 13:37:20 -070079 }
80
Mindy Pereira18529312011-06-28 11:00:52 -070081 /**
82 * Get a HashMap of address to RecipientEntry that contains all contact
83 * information for a contact with the provided address, if one exists. This
84 * may block the UI, so run it in an async task.
85 *
86 * @param context Context.
Daisuke Miyakawa72117472011-07-20 14:10:10 -070087 * @param inAddresses Array of addresses on which to perform the lookup.
mindyp16923ee2012-12-10 11:58:29 -080088 * @param callback RecipientMatchCallback called when a match or matches are found.
Mindy Pereira18529312011-06-28 11:00:52 -070089 * @return HashMap<String,RecipientEntry>
90 */
Alon Albert76f1f2d2013-07-14 15:32:49 +030091 public static void getMatchingRecipients(Context context, BaseRecipientAdapter adapter,
92 ArrayList<String> inAddresses, int addressType, Account account,
93 RecipientMatchCallback callback) {
Tom Taylor80f4abf2012-04-06 13:37:20 -070094 Queries.Query query;
95 if (addressType == QUERY_TYPE_EMAIL) {
96 query = Queries.EMAIL;
97 } else {
98 query = Queries.PHONE;
99 }
Mindy Pereira03cfe3e2012-05-24 13:21:59 -0700100 int addressesSize = Math.min(MAX_LOOKUPS, inAddresses.size());
mindyp16923ee2012-12-10 11:58:29 -0800101 HashSet<String> addresses = new HashSet<String>();
Mindy Pereira18529312011-06-28 11:00:52 -0700102 StringBuilder bindString = new StringBuilder();
103 // Create the "?" string and set up arguments.
104 for (int i = 0; i < addressesSize; i++) {
Mindy Pereira03cfe3e2012-05-24 13:21:59 -0700105 Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(inAddresses.get(i).toLowerCase());
mindyp16923ee2012-12-10 11:58:29 -0800106 addresses.add(tokens.length > 0 ? tokens[0].getAddress() : inAddresses.get(i));
Mindy Pereira18529312011-06-28 11:00:52 -0700107 bindString.append("?");
108 if (i < addressesSize - 1) {
109 bindString.append(",");
110 }
111 }
112
Mindy Pereira18987c42011-07-11 11:26:46 -0700113 if (Log.isLoggable(TAG, Log.DEBUG)) {
114 Log.d(TAG, "Doing reverse lookup for " + addresses.toString());
115 }
116
mindyp16923ee2012-12-10 11:58:29 -0800117 String[] addressArray = new String[addresses.size()];
118 addresses.toArray(addressArray);
119 HashMap<String, RecipientEntry> recipientEntries = null;
120 Cursor c = null;
Tom Taylor80f4abf2012-04-06 13:37:20 -0700121
mindyp16923ee2012-12-10 11:58:29 -0800122 try {
123 c = context.getContentResolver().query(
124 query.getContentUri(),
125 query.getProjection(),
126 query.getProjection()[Queries.Query.DESTINATION] + " IN ("
127 + bindString.toString() + ")", addressArray, null);
128 recipientEntries = processContactEntries(c);
129 callback.matchesFound(recipientEntries);
130 } finally {
131 if (c != null) {
Mindy Pereira18529312011-06-28 11:00:52 -0700132 c.close();
133 }
134 }
mindyp16923ee2012-12-10 11:58:29 -0800135 // See if any entries did not resolve; if so, we need to check other
136 // directories
Scott Kennedy94fa3012013-02-15 18:22:05 -0800137 final Set<String> matchesNotFound = new HashSet<String>();
mindyp16923ee2012-12-10 11:58:29 -0800138 if (recipientEntries.size() < addresses.size()) {
139 final List<DirectorySearchParams> paramsList;
Scott Kennedy539c2b12013-03-13 19:25:12 -0700140 Cursor directoryCursor = null;
141 try {
142 directoryCursor = context.getContentResolver().query(DirectoryListQuery.URI,
143 DirectoryListQuery.PROJECTION, null, null, null);
Scott Kennedy771e4172013-06-07 08:48:23 -0700144 if (directoryCursor == null) {
145 paramsList = null;
146 } else {
147 paramsList = BaseRecipientAdapter.setupOtherDirectories(context,
148 directoryCursor, account);
149 }
Scott Kennedy539c2b12013-03-13 19:25:12 -0700150 } finally {
151 if (directoryCursor != null) {
152 directoryCursor.close();
153 }
154 }
mindyp16923ee2012-12-10 11:58:29 -0800155 // Run a directory query for each unmatched recipient.
156 HashSet<String> unresolvedAddresses = new HashSet<String>();
157 for (String address : addresses) {
158 if (!recipientEntries.containsKey(address)) {
159 unresolvedAddresses.add(address);
160 }
161 }
Scott Kennedy94fa3012013-02-15 18:22:05 -0800162
163 matchesNotFound.addAll(unresolvedAddresses);
164
Scott Kennedy771e4172013-06-07 08:48:23 -0700165 if (paramsList != null) {
166 Cursor directoryContactsCursor = null;
167 for (String unresolvedAddress : unresolvedAddresses) {
168 for (int i = 0; i < paramsList.size(); i++) {
169 try {
170 directoryContactsCursor = doQuery(unresolvedAddress, 1,
171 paramsList.get(i).directoryId, account,
172 context.getContentResolver(), query);
173 } finally {
174 if (directoryContactsCursor != null
175 && directoryContactsCursor.getCount() == 0) {
176 directoryContactsCursor.close();
177 directoryContactsCursor = null;
178 } else {
179 break;
180 }
mindyp16923ee2012-12-10 11:58:29 -0800181 }
182 }
Scott Kennedy771e4172013-06-07 08:48:23 -0700183 if (directoryContactsCursor != null) {
184 try {
185 final Map<String, RecipientEntry> entries =
186 processContactEntries(directoryContactsCursor);
Scott Kennedy94fa3012013-02-15 18:22:05 -0800187
Scott Kennedy771e4172013-06-07 08:48:23 -0700188 for (final String address : entries.keySet()) {
189 matchesNotFound.remove(address);
190 }
191
192 callback.matchesFound(entries);
193 } finally {
194 directoryContactsCursor.close();
Scott Kennedy94fa3012013-02-15 18:22:05 -0800195 }
mindyp16923ee2012-12-10 11:58:29 -0800196 }
197 }
198 }
199 }
Scott Kennedy94fa3012013-02-15 18:22:05 -0800200
Alon Albert76f1f2d2013-07-14 15:32:49 +0300201 // If no matches found in contact provider or the directories, try the extension
202 // matcher.
203 // todo (aalbert): This whole method needs to be in the adapter?
204 if (adapter != null) {
205 final Map<String, RecipientEntry> entries =
206 adapter.getMatchingRecipients(matchesNotFound);
207 if (entries != null && entries.size() > 0) {
208 callback.matchesFound(entries);
209 for (final String address : entries.keySet()) {
210 matchesNotFound.remove(address);
211 }
212 }
213 }
Scott Kennedy94fa3012013-02-15 18:22:05 -0800214 callback.matchesNotFound(matchesNotFound);
mindyp16923ee2012-12-10 11:58:29 -0800215 }
216
217 private static HashMap<String, RecipientEntry> processContactEntries(Cursor c) {
218 HashMap<String, RecipientEntry> recipientEntries = new HashMap<String, RecipientEntry>();
219 if (c != null && c.moveToFirst()) {
220 do {
221 String address = c.getString(Queries.Query.DESTINATION);
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800222
223 final RecipientEntry newRecipientEntry = RecipientEntry.constructTopLevelEntry(
mindyp16923ee2012-12-10 11:58:29 -0800224 c.getString(Queries.Query.NAME),
225 c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
226 c.getString(Queries.Query.DESTINATION),
227 c.getInt(Queries.Query.DESTINATION_TYPE),
228 c.getString(Queries.Query.DESTINATION_LABEL),
229 c.getLong(Queries.Query.CONTACT_ID),
230 c.getLong(Queries.Query.DATA_ID),
231 c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
Scott Kennedy514f8a72013-11-13 15:58:08 -0800232 true,
233 false /* isGalContact TODO(skennedy) We should look these up eventually */);
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800234
235 /*
236 * In certain situations, we may have two results for one address, where one of the
237 * results is just the email address, and the other has a name and photo, so we want
238 * to use the better one.
239 */
240 final RecipientEntry recipientEntry =
241 getBetterRecipient(recipientEntries.get(address), newRecipientEntry);
242
243 recipientEntries.put(address, recipientEntry);
mindyp16923ee2012-12-10 11:58:29 -0800244 if (Log.isLoggable(TAG, Log.DEBUG)) {
245 Log.d(TAG, "Received reverse look up information for " + address
246 + " RESULTS: "
247 + " NAME : " + c.getString(Queries.Query.NAME)
248 + " CONTACT ID : " + c.getLong(Queries.Query.CONTACT_ID)
249 + " ADDRESS :" + c.getString(Queries.Query.DESTINATION));
250 }
251 } while (c.moveToNext());
252 }
Mindy Pereira18529312011-06-28 11:00:52 -0700253 return recipientEntries;
254 }
255
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800256 /**
257 * Given two {@link RecipientEntry}s for the same email address, this will return the one that
258 * contains more complete information for display purposes. Defaults to <code>entry2</code> if
259 * no significant differences are found.
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800260 */
Scott Kennedy78f38a02013-02-27 11:21:40 -0800261 static RecipientEntry getBetterRecipient(final RecipientEntry entry1,
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800262 final RecipientEntry entry2) {
263 // If only one has passed in, use it
264 if (entry2 == null) {
265 return entry1;
266 }
267
268 if (entry1 == null) {
269 return entry2;
270 }
271
272 // If only one has a display name, use it
273 if (!TextUtils.isEmpty(entry1.getDisplayName())
274 && TextUtils.isEmpty(entry2.getDisplayName())) {
275 return entry1;
276 }
277
278 if (!TextUtils.isEmpty(entry2.getDisplayName())
279 && TextUtils.isEmpty(entry1.getDisplayName())) {
280 return entry2;
281 }
282
283 // If only one has a display name that is not the same as the destination, use it
284 if (!TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())
285 && TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())) {
286 return entry1;
287 }
288
289 if (!TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())
290 && TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())) {
291 return entry2;
292 }
293
294 // If only one has a photo, use it
295 if ((entry1.getPhotoThumbnailUri() != null || entry1.getPhotoBytes() != null)
296 && (entry2.getPhotoThumbnailUri() == null && entry2.getPhotoBytes() == null)) {
297 return entry1;
298 }
299
300 if ((entry2.getPhotoThumbnailUri() != null || entry2.getPhotoBytes() != null)
301 && (entry1.getPhotoThumbnailUri() == null && entry1.getPhotoBytes() == null)) {
302 return entry2;
303 }
304
305 // Go with the second option as a default
306 return entry2;
307 }
308
mindyp16923ee2012-12-10 11:58:29 -0800309 private static Cursor doQuery(CharSequence constraint, int limit, Long directoryId,
310 Account account, ContentResolver resolver, Query query) {
311 final Uri.Builder builder = query
312 .getContentFilterUri()
313 .buildUpon()
314 .appendPath(constraint.toString())
315 .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
316 String.valueOf(limit + BaseRecipientAdapter.ALLOWANCE_FOR_DUPLICATES));
317 if (directoryId != null) {
318 builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
319 String.valueOf(directoryId));
320 }
321 if (account != null) {
322 builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_NAME, account.name);
323 builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_TYPE, account.type);
324 }
325 final Cursor cursor = resolver.query(builder.build(), query.getProjection(), null, null,
326 null);
327 return cursor;
328 }
329
Scott Kennedyf7e202d2013-03-06 21:38:10 -0800330 public RecipientAlternatesAdapter(Context context, long contactId, long currentId,
Mindy Pereira50863912011-06-16 18:54:10 -0700331 OnCheckedItemChangedListener listener) {
Scott Kennedyf7e202d2013-03-06 21:38:10 -0800332 this(context, contactId, currentId, QUERY_TYPE_EMAIL, listener);
Tom Taylor80f4abf2012-04-06 13:37:20 -0700333 }
334
Scott Kennedyf7e202d2013-03-06 21:38:10 -0800335 public RecipientAlternatesAdapter(Context context, long contactId, long currentId,
Tom Taylor80f4abf2012-04-06 13:37:20 -0700336 int queryMode, OnCheckedItemChangedListener listener) {
337 super(context, getCursorForConstruction(context, contactId, queryMode), 0);
Mindy Pereira97d77682011-06-01 10:48:55 -0700338 mLayoutInflater = LayoutInflater.from(context);
Mindy Pereira97d77682011-06-01 10:48:55 -0700339 mCurrentId = currentId;
Mindy Pereira50863912011-06-16 18:54:10 -0700340 mCheckedItemChangedListener = listener;
Tom Taylor80f4abf2012-04-06 13:37:20 -0700341
342 if (queryMode == QUERY_TYPE_EMAIL) {
343 mQuery = Queries.EMAIL;
344 } else if (queryMode == QUERY_TYPE_PHONE) {
345 mQuery = Queries.PHONE;
346 } else {
347 mQuery = Queries.EMAIL;
348 Log.e(TAG, "Unsupported query type: " + queryMode);
349 }
350 }
351
352 private static Cursor getCursorForConstruction(Context context, long contactId, int queryType) {
Makoto Onukia5d37c82012-05-03 13:40:45 -0700353 final Cursor cursor;
Tom Taylor80f4abf2012-04-06 13:37:20 -0700354 if (queryType == QUERY_TYPE_EMAIL) {
Makoto Onukia5d37c82012-05-03 13:40:45 -0700355 cursor = context.getContentResolver().query(
Tom Taylor80f4abf2012-04-06 13:37:20 -0700356 Queries.EMAIL.getContentUri(),
357 Queries.EMAIL.getProjection(),
Mindy Pereiraa62ba492012-04-24 16:34:26 -0700358 Queries.EMAIL.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700359 String.valueOf(contactId)
360 }, null);
361 } else {
Makoto Onukia5d37c82012-05-03 13:40:45 -0700362 cursor = context.getContentResolver().query(
Tom Taylor80f4abf2012-04-06 13:37:20 -0700363 Queries.PHONE.getContentUri(),
364 Queries.PHONE.getProjection(),
Tom Taylor9c17ab52012-04-25 13:53:36 -0700365 Queries.PHONE.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700366 String.valueOf(contactId)
367 }, null);
368 }
Makoto Onukia5d37c82012-05-03 13:40:45 -0700369 return removeDuplicateDestinations(cursor);
370 }
371
372 /**
373 * @return a new cursor based on the given cursor with all duplicate destinations removed.
374 *
375 * It's only intended to use for the alternate list, so...
376 * - This method ignores all other fields and dedupe solely on the destination. Normally,
377 * if a cursor contains multiple contacts and they have the same destination, we'd still want
378 * to show both.
379 * - This method creates a MatrixCursor, so all data will be kept in memory. We wouldn't want
380 * to do this if the original cursor is large, but it's okay here because the alternate list
381 * won't be that big.
382 */
383 // Visible for testing
384 /* package */ static Cursor removeDuplicateDestinations(Cursor original) {
385 final MatrixCursor result = new MatrixCursor(
386 original.getColumnNames(), original.getCount());
387 final HashSet<String> destinationsSeen = new HashSet<String>();
388
389 original.moveToPosition(-1);
390 while (original.moveToNext()) {
391 final String destination = original.getString(Query.DESTINATION);
392 if (destinationsSeen.contains(destination)) {
393 continue;
394 }
395 destinationsSeen.add(destination);
396
397 result.addRow(new Object[] {
398 original.getString(Query.NAME),
399 original.getString(Query.DESTINATION),
400 original.getInt(Query.DESTINATION_TYPE),
401 original.getString(Query.DESTINATION_LABEL),
402 original.getLong(Query.CONTACT_ID),
403 original.getLong(Query.DATA_ID),
404 original.getString(Query.PHOTO_THUMBNAIL_URI),
405 original.getInt(Query.DISPLAY_NAME_SOURCE)
406 });
407 }
408
409 return result;
Mindy Pereira97d77682011-06-01 10:48:55 -0700410 }
411
412 @Override
413 public long getItemId(int position) {
414 Cursor c = getCursor();
Mindy Pereira3bb52162011-07-01 14:52:22 -0700415 if (c.moveToPosition(position)) {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700416 c.getLong(Queries.Query.DATA_ID);
Mindy Pereira3bb52162011-07-01 14:52:22 -0700417 }
418 return -1;
Mindy Pereira97d77682011-06-01 10:48:55 -0700419 }
420
421 public RecipientEntry getRecipientEntry(int position) {
422 Cursor c = getCursor();
423 c.moveToPosition(position);
Tom Taylor80f4abf2012-04-06 13:37:20 -0700424 return RecipientEntry.constructTopLevelEntry(
425 c.getString(Queries.Query.NAME),
Makoto Onuki00adb322012-05-01 16:50:41 -0700426 c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
Tom Taylor80f4abf2012-04-06 13:37:20 -0700427 c.getString(Queries.Query.DESTINATION),
428 c.getInt(Queries.Query.DESTINATION_TYPE),
429 c.getString(Queries.Query.DESTINATION_LABEL),
430 c.getLong(Queries.Query.CONTACT_ID),
431 c.getLong(Queries.Query.DATA_ID),
mindypccb8e232012-11-14 11:59:27 -0800432 c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
Scott Kennedy514f8a72013-11-13 15:58:08 -0800433 true,
434 false /* isGalContact TODO(skennedy) We should look these up eventually */);
Mindy Pereira97d77682011-06-01 10:48:55 -0700435 }
436
437 @Override
438 public View getView(int position, View convertView, ViewGroup parent) {
Mindy Pereira67ad4892011-06-02 12:21:22 -0700439 Cursor cursor = getCursor();
440 cursor.moveToPosition(position);
Mindy Pereira97d77682011-06-01 10:48:55 -0700441 if (convertView == null) {
Mindy Pereira007a76b2011-06-14 11:39:36 -0700442 convertView = newView();
443 }
Tom Taylor80f4abf2012-04-06 13:37:20 -0700444 if (cursor.getLong(Queries.Query.DATA_ID) == mCurrentId) {
Mindy Pereira007a76b2011-06-14 11:39:36 -0700445 mCheckedItemPosition = position;
Mindy Pereira50863912011-06-16 18:54:10 -0700446 if (mCheckedItemChangedListener != null) {
447 mCheckedItemChangedListener.onCheckedItemChanged(mCheckedItemPosition);
448 }
Mindy Pereira97d77682011-06-01 10:48:55 -0700449 }
Mindy Pereira67ad4892011-06-02 12:21:22 -0700450 bindView(convertView, convertView.getContext(), cursor);
Mindy Pereira97d77682011-06-01 10:48:55 -0700451 return convertView;
452 }
453
Mindy Pereira67ad4892011-06-02 12:21:22 -0700454 // TODO: this is VERY similar to the BaseRecipientAdapter. Can we combine
455 // somehow?
Mindy Pereira97d77682011-06-01 10:48:55 -0700456 @Override
457 public void bindView(View view, Context context, Cursor cursor) {
Mindy Pereira67ad4892011-06-02 12:21:22 -0700458 int position = cursor.getPosition();
459
Daisuke Miyakawa102cf102011-07-21 08:48:27 -0700460 TextView display = (TextView) view.findViewById(android.R.id.title);
Mindy Pereira67ad4892011-06-02 12:21:22 -0700461 ImageView imageView = (ImageView) view.findViewById(android.R.id.icon);
462 RecipientEntry entry = getRecipientEntry(position);
463 if (position == 0) {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700464 display.setText(cursor.getString(Queries.Query.NAME));
Mindy Pereira67ad4892011-06-02 12:21:22 -0700465 display.setVisibility(View.VISIBLE);
466 // TODO: see if this needs to be done outside the main thread
467 // as it may be too slow to get immediately.
468 imageView.setImageURI(entry.getPhotoThumbnailUri());
469 imageView.setVisibility(View.VISIBLE);
470 } else {
471 display.setVisibility(View.GONE);
472 imageView.setVisibility(View.GONE);
473 }
Daisuke Miyakawa102cf102011-07-21 08:48:27 -0700474 TextView destination = (TextView) view.findViewById(android.R.id.text1);
Tom Taylor80f4abf2012-04-06 13:37:20 -0700475 destination.setText(cursor.getString(Queries.Query.DESTINATION));
Daisuke Miyakawa102cf102011-07-21 08:48:27 -0700476
477 TextView destinationType = (TextView) view.findViewById(android.R.id.text2);
Mindy Pereiraf908b642011-08-29 10:56:15 -0700478 if (destinationType != null) {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700479 destinationType.setText(mQuery.getTypeLabel(context.getResources(),
480 cursor.getInt(Queries.Query.DESTINATION_TYPE),
481 cursor.getString(Queries.Query.DESTINATION_LABEL)).toString().toUpperCase());
Mindy Pereiraf908b642011-08-29 10:56:15 -0700482 }
Mindy Pereira97d77682011-06-01 10:48:55 -0700483 }
484
485 @Override
486 public View newView(Context context, Cursor cursor, ViewGroup parent) {
Mindy Pereira007a76b2011-06-14 11:39:36 -0700487 return newView();
Mindy Pereira97d77682011-06-01 10:48:55 -0700488 }
489
Mindy Pereira007a76b2011-06-14 11:39:36 -0700490 private View newView() {
Mindy Pereira52c441e2011-12-15 13:35:37 -0800491 return mLayoutInflater.inflate(R.layout.chips_recipient_dropdown_item, null);
Mindy Pereira007a76b2011-06-14 11:39:36 -0700492 }
493
Mindy Pereira50863912011-06-16 18:54:10 -0700494 /*package*/ static interface OnCheckedItemChangedListener {
495 public void onCheckedItemChanged(int position);
Mindy Pereira97d77682011-06-01 10:48:55 -0700496 }
497}