blob: ef343796f974f0c1be44f0b34ad218fad66771b7 [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
76 public static void getMatchingRecipients(Context context, ArrayList<String> inAddresses,
77 Account account, RecipientMatchCallback callback) {
78 getMatchingRecipients(context, 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 */
mindyp16923ee2012-12-10 11:58:29 -080091 public static void getMatchingRecipients(Context context, ArrayList<String> inAddresses,
92 int addressType, Account account, RecipientMatchCallback callback) {
Tom Taylor80f4abf2012-04-06 13:37:20 -070093 Queries.Query query;
94 if (addressType == QUERY_TYPE_EMAIL) {
95 query = Queries.EMAIL;
96 } else {
97 query = Queries.PHONE;
98 }
Mindy Pereira03cfe3e2012-05-24 13:21:59 -070099 int addressesSize = Math.min(MAX_LOOKUPS, inAddresses.size());
mindyp16923ee2012-12-10 11:58:29 -0800100 HashSet<String> addresses = new HashSet<String>();
Mindy Pereira18529312011-06-28 11:00:52 -0700101 StringBuilder bindString = new StringBuilder();
102 // Create the "?" string and set up arguments.
103 for (int i = 0; i < addressesSize; i++) {
Mindy Pereira03cfe3e2012-05-24 13:21:59 -0700104 Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(inAddresses.get(i).toLowerCase());
mindyp16923ee2012-12-10 11:58:29 -0800105 addresses.add(tokens.length > 0 ? tokens[0].getAddress() : inAddresses.get(i));
Mindy Pereira18529312011-06-28 11:00:52 -0700106 bindString.append("?");
107 if (i < addressesSize - 1) {
108 bindString.append(",");
109 }
110 }
111
Mindy Pereira18987c42011-07-11 11:26:46 -0700112 if (Log.isLoggable(TAG, Log.DEBUG)) {
113 Log.d(TAG, "Doing reverse lookup for " + addresses.toString());
114 }
115
mindyp16923ee2012-12-10 11:58:29 -0800116 String[] addressArray = new String[addresses.size()];
117 addresses.toArray(addressArray);
118 HashMap<String, RecipientEntry> recipientEntries = null;
119 Cursor c = null;
Tom Taylor80f4abf2012-04-06 13:37:20 -0700120
mindyp16923ee2012-12-10 11:58:29 -0800121 try {
122 c = context.getContentResolver().query(
123 query.getContentUri(),
124 query.getProjection(),
125 query.getProjection()[Queries.Query.DESTINATION] + " IN ("
126 + bindString.toString() + ")", addressArray, null);
127 recipientEntries = processContactEntries(c);
128 callback.matchesFound(recipientEntries);
129 } finally {
130 if (c != null) {
Mindy Pereira18529312011-06-28 11:00:52 -0700131 c.close();
132 }
133 }
mindyp16923ee2012-12-10 11:58:29 -0800134 // See if any entries did not resolve; if so, we need to check other
135 // directories
Scott Kennedy94fa3012013-02-15 18:22:05 -0800136 final Set<String> matchesNotFound = new HashSet<String>();
mindyp16923ee2012-12-10 11:58:29 -0800137 if (recipientEntries.size() < addresses.size()) {
138 final List<DirectorySearchParams> paramsList;
Scott Kennedy539c2b12013-03-13 19:25:12 -0700139 Cursor directoryCursor = null;
140 try {
141 directoryCursor = context.getContentResolver().query(DirectoryListQuery.URI,
142 DirectoryListQuery.PROJECTION, null, null, null);
Scott Kennedy771e4172013-06-07 08:48:23 -0700143 if (directoryCursor == null) {
144 paramsList = null;
145 } else {
146 paramsList = BaseRecipientAdapter.setupOtherDirectories(context,
147 directoryCursor, account);
148 }
Scott Kennedy539c2b12013-03-13 19:25:12 -0700149 } finally {
150 if (directoryCursor != null) {
151 directoryCursor.close();
152 }
153 }
mindyp16923ee2012-12-10 11:58:29 -0800154 // Run a directory query for each unmatched recipient.
155 HashSet<String> unresolvedAddresses = new HashSet<String>();
156 for (String address : addresses) {
157 if (!recipientEntries.containsKey(address)) {
158 unresolvedAddresses.add(address);
159 }
160 }
Scott Kennedy94fa3012013-02-15 18:22:05 -0800161
162 matchesNotFound.addAll(unresolvedAddresses);
163
Scott Kennedy771e4172013-06-07 08:48:23 -0700164 if (paramsList != null) {
165 Cursor directoryContactsCursor = null;
166 for (String unresolvedAddress : unresolvedAddresses) {
167 for (int i = 0; i < paramsList.size(); i++) {
168 try {
169 directoryContactsCursor = doQuery(unresolvedAddress, 1,
170 paramsList.get(i).directoryId, account,
171 context.getContentResolver(), query);
172 } finally {
173 if (directoryContactsCursor != null
174 && directoryContactsCursor.getCount() == 0) {
175 directoryContactsCursor.close();
176 directoryContactsCursor = null;
177 } else {
178 break;
179 }
mindyp16923ee2012-12-10 11:58:29 -0800180 }
181 }
Scott Kennedy771e4172013-06-07 08:48:23 -0700182 if (directoryContactsCursor != null) {
183 try {
184 final Map<String, RecipientEntry> entries =
185 processContactEntries(directoryContactsCursor);
Scott Kennedy94fa3012013-02-15 18:22:05 -0800186
Scott Kennedy771e4172013-06-07 08:48:23 -0700187 for (final String address : entries.keySet()) {
188 matchesNotFound.remove(address);
189 }
190
191 callback.matchesFound(entries);
192 } finally {
193 directoryContactsCursor.close();
Scott Kennedy94fa3012013-02-15 18:22:05 -0800194 }
mindyp16923ee2012-12-10 11:58:29 -0800195 }
196 }
197 }
198 }
Scott Kennedy94fa3012013-02-15 18:22:05 -0800199
200 callback.matchesNotFound(matchesNotFound);
mindyp16923ee2012-12-10 11:58:29 -0800201 }
202
203 private static HashMap<String, RecipientEntry> processContactEntries(Cursor c) {
204 HashMap<String, RecipientEntry> recipientEntries = new HashMap<String, RecipientEntry>();
205 if (c != null && c.moveToFirst()) {
206 do {
207 String address = c.getString(Queries.Query.DESTINATION);
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800208
209 final RecipientEntry newRecipientEntry = RecipientEntry.constructTopLevelEntry(
mindyp16923ee2012-12-10 11:58:29 -0800210 c.getString(Queries.Query.NAME),
211 c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
212 c.getString(Queries.Query.DESTINATION),
213 c.getInt(Queries.Query.DESTINATION_TYPE),
214 c.getString(Queries.Query.DESTINATION_LABEL),
215 c.getLong(Queries.Query.CONTACT_ID),
216 c.getLong(Queries.Query.DATA_ID),
217 c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800218 true);
219
220 /*
221 * In certain situations, we may have two results for one address, where one of the
222 * results is just the email address, and the other has a name and photo, so we want
223 * to use the better one.
224 */
225 final RecipientEntry recipientEntry =
226 getBetterRecipient(recipientEntries.get(address), newRecipientEntry);
227
228 recipientEntries.put(address, recipientEntry);
mindyp16923ee2012-12-10 11:58:29 -0800229 if (Log.isLoggable(TAG, Log.DEBUG)) {
230 Log.d(TAG, "Received reverse look up information for " + address
231 + " RESULTS: "
232 + " NAME : " + c.getString(Queries.Query.NAME)
233 + " CONTACT ID : " + c.getLong(Queries.Query.CONTACT_ID)
234 + " ADDRESS :" + c.getString(Queries.Query.DESTINATION));
235 }
236 } while (c.moveToNext());
237 }
Mindy Pereira18529312011-06-28 11:00:52 -0700238 return recipientEntries;
239 }
240
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800241 /**
242 * Given two {@link RecipientEntry}s for the same email address, this will return the one that
243 * contains more complete information for display purposes. Defaults to <code>entry2</code> if
244 * no significant differences are found.
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800245 */
Scott Kennedy78f38a02013-02-27 11:21:40 -0800246 static RecipientEntry getBetterRecipient(final RecipientEntry entry1,
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800247 final RecipientEntry entry2) {
248 // If only one has passed in, use it
249 if (entry2 == null) {
250 return entry1;
251 }
252
253 if (entry1 == null) {
254 return entry2;
255 }
256
257 // If only one has a display name, use it
258 if (!TextUtils.isEmpty(entry1.getDisplayName())
259 && TextUtils.isEmpty(entry2.getDisplayName())) {
260 return entry1;
261 }
262
263 if (!TextUtils.isEmpty(entry2.getDisplayName())
264 && TextUtils.isEmpty(entry1.getDisplayName())) {
265 return entry2;
266 }
267
268 // If only one has a display name that is not the same as the destination, use it
269 if (!TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())
270 && TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())) {
271 return entry1;
272 }
273
274 if (!TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())
275 && TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())) {
276 return entry2;
277 }
278
279 // If only one has a photo, use it
280 if ((entry1.getPhotoThumbnailUri() != null || entry1.getPhotoBytes() != null)
281 && (entry2.getPhotoThumbnailUri() == null && entry2.getPhotoBytes() == null)) {
282 return entry1;
283 }
284
285 if ((entry2.getPhotoThumbnailUri() != null || entry2.getPhotoBytes() != null)
286 && (entry1.getPhotoThumbnailUri() == null && entry1.getPhotoBytes() == null)) {
287 return entry2;
288 }
289
290 // Go with the second option as a default
291 return entry2;
292 }
293
mindyp16923ee2012-12-10 11:58:29 -0800294 private static Cursor doQuery(CharSequence constraint, int limit, Long directoryId,
295 Account account, ContentResolver resolver, Query query) {
296 final Uri.Builder builder = query
297 .getContentFilterUri()
298 .buildUpon()
299 .appendPath(constraint.toString())
300 .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
301 String.valueOf(limit + BaseRecipientAdapter.ALLOWANCE_FOR_DUPLICATES));
302 if (directoryId != null) {
303 builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
304 String.valueOf(directoryId));
305 }
306 if (account != null) {
307 builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_NAME, account.name);
308 builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_TYPE, account.type);
309 }
310 final Cursor cursor = resolver.query(builder.build(), query.getProjection(), null, null,
311 null);
312 return cursor;
313 }
314
Scott Kennedyf7e202d2013-03-06 21:38:10 -0800315 public RecipientAlternatesAdapter(Context context, long contactId, long currentId,
Mindy Pereira50863912011-06-16 18:54:10 -0700316 OnCheckedItemChangedListener listener) {
Scott Kennedyf7e202d2013-03-06 21:38:10 -0800317 this(context, contactId, currentId, QUERY_TYPE_EMAIL, listener);
Tom Taylor80f4abf2012-04-06 13:37:20 -0700318 }
319
Scott Kennedyf7e202d2013-03-06 21:38:10 -0800320 public RecipientAlternatesAdapter(Context context, long contactId, long currentId,
Tom Taylor80f4abf2012-04-06 13:37:20 -0700321 int queryMode, OnCheckedItemChangedListener listener) {
322 super(context, getCursorForConstruction(context, contactId, queryMode), 0);
Mindy Pereira97d77682011-06-01 10:48:55 -0700323 mLayoutInflater = LayoutInflater.from(context);
Mindy Pereira97d77682011-06-01 10:48:55 -0700324 mCurrentId = currentId;
Mindy Pereira50863912011-06-16 18:54:10 -0700325 mCheckedItemChangedListener = listener;
Tom Taylor80f4abf2012-04-06 13:37:20 -0700326
327 if (queryMode == QUERY_TYPE_EMAIL) {
328 mQuery = Queries.EMAIL;
329 } else if (queryMode == QUERY_TYPE_PHONE) {
330 mQuery = Queries.PHONE;
331 } else {
332 mQuery = Queries.EMAIL;
333 Log.e(TAG, "Unsupported query type: " + queryMode);
334 }
335 }
336
337 private static Cursor getCursorForConstruction(Context context, long contactId, int queryType) {
Makoto Onukia5d37c82012-05-03 13:40:45 -0700338 final Cursor cursor;
Tom Taylor80f4abf2012-04-06 13:37:20 -0700339 if (queryType == QUERY_TYPE_EMAIL) {
Makoto Onukia5d37c82012-05-03 13:40:45 -0700340 cursor = context.getContentResolver().query(
Tom Taylor80f4abf2012-04-06 13:37:20 -0700341 Queries.EMAIL.getContentUri(),
342 Queries.EMAIL.getProjection(),
Mindy Pereiraa62ba492012-04-24 16:34:26 -0700343 Queries.EMAIL.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700344 String.valueOf(contactId)
345 }, null);
346 } else {
Makoto Onukia5d37c82012-05-03 13:40:45 -0700347 cursor = context.getContentResolver().query(
Tom Taylor80f4abf2012-04-06 13:37:20 -0700348 Queries.PHONE.getContentUri(),
349 Queries.PHONE.getProjection(),
Tom Taylor9c17ab52012-04-25 13:53:36 -0700350 Queries.PHONE.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700351 String.valueOf(contactId)
352 }, null);
353 }
Makoto Onukia5d37c82012-05-03 13:40:45 -0700354 return removeDuplicateDestinations(cursor);
355 }
356
357 /**
358 * @return a new cursor based on the given cursor with all duplicate destinations removed.
359 *
360 * It's only intended to use for the alternate list, so...
361 * - This method ignores all other fields and dedupe solely on the destination. Normally,
362 * if a cursor contains multiple contacts and they have the same destination, we'd still want
363 * to show both.
364 * - This method creates a MatrixCursor, so all data will be kept in memory. We wouldn't want
365 * to do this if the original cursor is large, but it's okay here because the alternate list
366 * won't be that big.
367 */
368 // Visible for testing
369 /* package */ static Cursor removeDuplicateDestinations(Cursor original) {
370 final MatrixCursor result = new MatrixCursor(
371 original.getColumnNames(), original.getCount());
372 final HashSet<String> destinationsSeen = new HashSet<String>();
373
374 original.moveToPosition(-1);
375 while (original.moveToNext()) {
376 final String destination = original.getString(Query.DESTINATION);
377 if (destinationsSeen.contains(destination)) {
378 continue;
379 }
380 destinationsSeen.add(destination);
381
382 result.addRow(new Object[] {
383 original.getString(Query.NAME),
384 original.getString(Query.DESTINATION),
385 original.getInt(Query.DESTINATION_TYPE),
386 original.getString(Query.DESTINATION_LABEL),
387 original.getLong(Query.CONTACT_ID),
388 original.getLong(Query.DATA_ID),
389 original.getString(Query.PHOTO_THUMBNAIL_URI),
390 original.getInt(Query.DISPLAY_NAME_SOURCE)
391 });
392 }
393
394 return result;
Mindy Pereira97d77682011-06-01 10:48:55 -0700395 }
396
397 @Override
398 public long getItemId(int position) {
399 Cursor c = getCursor();
Mindy Pereira3bb52162011-07-01 14:52:22 -0700400 if (c.moveToPosition(position)) {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700401 c.getLong(Queries.Query.DATA_ID);
Mindy Pereira3bb52162011-07-01 14:52:22 -0700402 }
403 return -1;
Mindy Pereira97d77682011-06-01 10:48:55 -0700404 }
405
406 public RecipientEntry getRecipientEntry(int position) {
407 Cursor c = getCursor();
408 c.moveToPosition(position);
Tom Taylor80f4abf2012-04-06 13:37:20 -0700409 return RecipientEntry.constructTopLevelEntry(
410 c.getString(Queries.Query.NAME),
Makoto Onuki00adb322012-05-01 16:50:41 -0700411 c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
Tom Taylor80f4abf2012-04-06 13:37:20 -0700412 c.getString(Queries.Query.DESTINATION),
413 c.getInt(Queries.Query.DESTINATION_TYPE),
414 c.getString(Queries.Query.DESTINATION_LABEL),
415 c.getLong(Queries.Query.CONTACT_ID),
416 c.getLong(Queries.Query.DATA_ID),
mindypccb8e232012-11-14 11:59:27 -0800417 c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
418 true);
Mindy Pereira97d77682011-06-01 10:48:55 -0700419 }
420
421 @Override
422 public View getView(int position, View convertView, ViewGroup parent) {
Mindy Pereira67ad4892011-06-02 12:21:22 -0700423 Cursor cursor = getCursor();
424 cursor.moveToPosition(position);
Mindy Pereira97d77682011-06-01 10:48:55 -0700425 if (convertView == null) {
Mindy Pereira007a76b2011-06-14 11:39:36 -0700426 convertView = newView();
427 }
Tom Taylor80f4abf2012-04-06 13:37:20 -0700428 if (cursor.getLong(Queries.Query.DATA_ID) == mCurrentId) {
Mindy Pereira007a76b2011-06-14 11:39:36 -0700429 mCheckedItemPosition = position;
Mindy Pereira50863912011-06-16 18:54:10 -0700430 if (mCheckedItemChangedListener != null) {
431 mCheckedItemChangedListener.onCheckedItemChanged(mCheckedItemPosition);
432 }
Mindy Pereira97d77682011-06-01 10:48:55 -0700433 }
Mindy Pereira67ad4892011-06-02 12:21:22 -0700434 bindView(convertView, convertView.getContext(), cursor);
Mindy Pereira97d77682011-06-01 10:48:55 -0700435 return convertView;
436 }
437
Mindy Pereira67ad4892011-06-02 12:21:22 -0700438 // TODO: this is VERY similar to the BaseRecipientAdapter. Can we combine
439 // somehow?
Mindy Pereira97d77682011-06-01 10:48:55 -0700440 @Override
441 public void bindView(View view, Context context, Cursor cursor) {
Mindy Pereira67ad4892011-06-02 12:21:22 -0700442 int position = cursor.getPosition();
443
Daisuke Miyakawa102cf102011-07-21 08:48:27 -0700444 TextView display = (TextView) view.findViewById(android.R.id.title);
Mindy Pereira67ad4892011-06-02 12:21:22 -0700445 ImageView imageView = (ImageView) view.findViewById(android.R.id.icon);
446 RecipientEntry entry = getRecipientEntry(position);
447 if (position == 0) {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700448 display.setText(cursor.getString(Queries.Query.NAME));
Mindy Pereira67ad4892011-06-02 12:21:22 -0700449 display.setVisibility(View.VISIBLE);
450 // TODO: see if this needs to be done outside the main thread
451 // as it may be too slow to get immediately.
452 imageView.setImageURI(entry.getPhotoThumbnailUri());
453 imageView.setVisibility(View.VISIBLE);
454 } else {
455 display.setVisibility(View.GONE);
456 imageView.setVisibility(View.GONE);
457 }
Daisuke Miyakawa102cf102011-07-21 08:48:27 -0700458 TextView destination = (TextView) view.findViewById(android.R.id.text1);
Tom Taylor80f4abf2012-04-06 13:37:20 -0700459 destination.setText(cursor.getString(Queries.Query.DESTINATION));
Daisuke Miyakawa102cf102011-07-21 08:48:27 -0700460
461 TextView destinationType = (TextView) view.findViewById(android.R.id.text2);
Mindy Pereiraf908b642011-08-29 10:56:15 -0700462 if (destinationType != null) {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700463 destinationType.setText(mQuery.getTypeLabel(context.getResources(),
464 cursor.getInt(Queries.Query.DESTINATION_TYPE),
465 cursor.getString(Queries.Query.DESTINATION_LABEL)).toString().toUpperCase());
Mindy Pereiraf908b642011-08-29 10:56:15 -0700466 }
Mindy Pereira97d77682011-06-01 10:48:55 -0700467 }
468
469 @Override
470 public View newView(Context context, Cursor cursor, ViewGroup parent) {
Mindy Pereira007a76b2011-06-14 11:39:36 -0700471 return newView();
Mindy Pereira97d77682011-06-01 10:48:55 -0700472 }
473
Mindy Pereira007a76b2011-06-14 11:39:36 -0700474 private View newView() {
Mindy Pereira52c441e2011-12-15 13:35:37 -0800475 return mLayoutInflater.inflate(R.layout.chips_recipient_dropdown_item, null);
Mindy Pereira007a76b2011-06-14 11:39:36 -0700476 }
477
Mindy Pereira50863912011-06-16 18:54:10 -0700478 /*package*/ static interface OnCheckedItemChangedListener {
479 public void onCheckedItemChanged(int position);
Mindy Pereira97d77682011-06-01 10:48:55 -0700480 }
481}