blob: 547a76bae4da15b69a88c6316006d11b49c87eee [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.View;
31import android.view.ViewGroup;
32import android.widget.CursorAdapter;
Mindy Pereira97d77682011-06-01 10:48:55 -070033
mindyp16923ee2012-12-10 11:58:29 -080034import com.android.ex.chips.BaseRecipientAdapter.DirectoryListQuery;
35import com.android.ex.chips.BaseRecipientAdapter.DirectorySearchParams;
Kevin Linb10d1c62014-01-24 12:45:00 -080036import com.android.ex.chips.DropdownChipLayouter.AdapterType;
Tom Taylor80f4abf2012-04-06 13:37:20 -070037import com.android.ex.chips.Queries.Query;
Makoto Onukia5d37c82012-05-03 13:40:45 -070038
Mindy Pereira03cfe3e2012-05-24 13:21:59 -070039import java.util.ArrayList;
Mindy Pereira18529312011-06-28 11:00:52 -070040import java.util.HashMap;
Makoto Onukia5d37c82012-05-03 13:40:45 -070041import java.util.HashSet;
mindyp16923ee2012-12-10 11:58:29 -080042import java.util.List;
Scott Kennedy94fa3012013-02-15 18:22:05 -080043import java.util.Map;
44import java.util.Set;
Mindy Pereira18529312011-06-28 11:00:52 -070045
Tom Taylor80f4abf2012-04-06 13:37:20 -070046/**
47 * RecipientAlternatesAdapter backs the RecipientEditTextView for managing contacts
48 * queried by email or by phone number.
49 */
Mindy Pereira97d77682011-06-01 10:48:55 -070050public class RecipientAlternatesAdapter extends CursorAdapter {
Mindy Pereira18529312011-06-28 11:00:52 -070051 static final int MAX_LOOKUPS = 50;
Mindy Pereira97d77682011-06-01 10:48:55 -070052
Mindy Pereira97d77682011-06-01 10:48:55 -070053 private final long mCurrentId;
54
Mindy Pereira007a76b2011-06-14 11:39:36 -070055 private int mCheckedItemPosition = -1;
56
Mindy Pereira50863912011-06-16 18:54:10 -070057 private OnCheckedItemChangedListener mCheckedItemChangedListener;
58
Mindy Pereira18987c42011-07-11 11:26:46 -070059 private static final String TAG = "RecipAlternates";
60
Tom Taylor80f4abf2012-04-06 13:37:20 -070061 public static final int QUERY_TYPE_EMAIL = 0;
62 public static final int QUERY_TYPE_PHONE = 1;
63 private Query mQuery;
Kevin Linb10d1c62014-01-24 12:45:00 -080064 private DropdownChipLayouter mDropdownChipLayouter;
Tom Taylor80f4abf2012-04-06 13:37:20 -070065
mindyp16923ee2012-12-10 11:58:29 -080066 public interface RecipientMatchCallback {
Scott Kennedy94fa3012013-02-15 18:22:05 -080067 public void matchesFound(Map<String, RecipientEntry> results);
68 /**
69 * Called with all addresses that could not be resolved to valid recipients.
70 */
Scott Kennedyf7e202d2013-03-06 21:38:10 -080071 public void matchesNotFound(Set<String> unfoundAddresses);
mindyp16923ee2012-12-10 11:58:29 -080072 }
73
Alon Albert76f1f2d2013-07-14 15:32:49 +030074 public static void getMatchingRecipients(Context context, BaseRecipientAdapter adapter,
75 ArrayList<String> inAddresses, Account account, RecipientMatchCallback callback) {
76 getMatchingRecipients(context, adapter, inAddresses, QUERY_TYPE_EMAIL, account, callback);
Tom Taylor80f4abf2012-04-06 13:37:20 -070077 }
78
Mindy Pereira18529312011-06-28 11:00:52 -070079 /**
80 * Get a HashMap of address to RecipientEntry that contains all contact
81 * information for a contact with the provided address, if one exists. This
82 * may block the UI, so run it in an async task.
83 *
84 * @param context Context.
Daisuke Miyakawa72117472011-07-20 14:10:10 -070085 * @param inAddresses Array of addresses on which to perform the lookup.
mindyp16923ee2012-12-10 11:58:29 -080086 * @param callback RecipientMatchCallback called when a match or matches are found.
Mindy Pereira18529312011-06-28 11:00:52 -070087 * @return HashMap<String,RecipientEntry>
88 */
Alon Albert76f1f2d2013-07-14 15:32:49 +030089 public static void getMatchingRecipients(Context context, BaseRecipientAdapter adapter,
90 ArrayList<String> inAddresses, int addressType, Account account,
91 RecipientMatchCallback callback) {
Tom Taylor80f4abf2012-04-06 13:37:20 -070092 Queries.Query query;
93 if (addressType == QUERY_TYPE_EMAIL) {
94 query = Queries.EMAIL;
95 } else {
96 query = Queries.PHONE;
97 }
Mindy Pereira03cfe3e2012-05-24 13:21:59 -070098 int addressesSize = Math.min(MAX_LOOKUPS, inAddresses.size());
mindyp16923ee2012-12-10 11:58:29 -080099 HashSet<String> addresses = new HashSet<String>();
Mindy Pereira18529312011-06-28 11:00:52 -0700100 StringBuilder bindString = new StringBuilder();
101 // Create the "?" string and set up arguments.
102 for (int i = 0; i < addressesSize; i++) {
Mindy Pereira03cfe3e2012-05-24 13:21:59 -0700103 Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(inAddresses.get(i).toLowerCase());
mindyp16923ee2012-12-10 11:58:29 -0800104 addresses.add(tokens.length > 0 ? tokens[0].getAddress() : inAddresses.get(i));
Mindy Pereira18529312011-06-28 11:00:52 -0700105 bindString.append("?");
106 if (i < addressesSize - 1) {
107 bindString.append(",");
108 }
109 }
110
Mindy Pereira18987c42011-07-11 11:26:46 -0700111 if (Log.isLoggable(TAG, Log.DEBUG)) {
112 Log.d(TAG, "Doing reverse lookup for " + addresses.toString());
113 }
114
mindyp16923ee2012-12-10 11:58:29 -0800115 String[] addressArray = new String[addresses.size()];
116 addresses.toArray(addressArray);
117 HashMap<String, RecipientEntry> recipientEntries = null;
118 Cursor c = null;
Tom Taylor80f4abf2012-04-06 13:37:20 -0700119
mindyp16923ee2012-12-10 11:58:29 -0800120 try {
121 c = context.getContentResolver().query(
122 query.getContentUri(),
123 query.getProjection(),
124 query.getProjection()[Queries.Query.DESTINATION] + " IN ("
125 + bindString.toString() + ")", addressArray, null);
126 recipientEntries = processContactEntries(c);
127 callback.matchesFound(recipientEntries);
128 } finally {
129 if (c != null) {
Mindy Pereira18529312011-06-28 11:00:52 -0700130 c.close();
131 }
132 }
mindyp16923ee2012-12-10 11:58:29 -0800133 // See if any entries did not resolve; if so, we need to check other
134 // directories
Scott Kennedy94fa3012013-02-15 18:22:05 -0800135 final Set<String> matchesNotFound = new HashSet<String>();
mindyp16923ee2012-12-10 11:58:29 -0800136 if (recipientEntries.size() < addresses.size()) {
137 final List<DirectorySearchParams> paramsList;
Scott Kennedy539c2b12013-03-13 19:25:12 -0700138 Cursor directoryCursor = null;
139 try {
140 directoryCursor = context.getContentResolver().query(DirectoryListQuery.URI,
141 DirectoryListQuery.PROJECTION, null, null, null);
Scott Kennedy771e4172013-06-07 08:48:23 -0700142 if (directoryCursor == null) {
143 paramsList = null;
144 } else {
145 paramsList = BaseRecipientAdapter.setupOtherDirectories(context,
146 directoryCursor, account);
147 }
Scott Kennedy539c2b12013-03-13 19:25:12 -0700148 } finally {
149 if (directoryCursor != null) {
150 directoryCursor.close();
151 }
152 }
mindyp16923ee2012-12-10 11:58:29 -0800153 // Run a directory query for each unmatched recipient.
154 HashSet<String> unresolvedAddresses = new HashSet<String>();
155 for (String address : addresses) {
156 if (!recipientEntries.containsKey(address)) {
157 unresolvedAddresses.add(address);
158 }
159 }
Scott Kennedy94fa3012013-02-15 18:22:05 -0800160
161 matchesNotFound.addAll(unresolvedAddresses);
162
Scott Kennedy771e4172013-06-07 08:48:23 -0700163 if (paramsList != null) {
164 Cursor directoryContactsCursor = null;
165 for (String unresolvedAddress : unresolvedAddresses) {
166 for (int i = 0; i < paramsList.size(); i++) {
167 try {
168 directoryContactsCursor = doQuery(unresolvedAddress, 1,
169 paramsList.get(i).directoryId, account,
170 context.getContentResolver(), query);
171 } finally {
172 if (directoryContactsCursor != null
173 && directoryContactsCursor.getCount() == 0) {
174 directoryContactsCursor.close();
175 directoryContactsCursor = null;
176 } else {
177 break;
178 }
mindyp16923ee2012-12-10 11:58:29 -0800179 }
180 }
Scott Kennedy771e4172013-06-07 08:48:23 -0700181 if (directoryContactsCursor != null) {
182 try {
183 final Map<String, RecipientEntry> entries =
184 processContactEntries(directoryContactsCursor);
Scott Kennedy94fa3012013-02-15 18:22:05 -0800185
Scott Kennedy771e4172013-06-07 08:48:23 -0700186 for (final String address : entries.keySet()) {
187 matchesNotFound.remove(address);
188 }
189
190 callback.matchesFound(entries);
191 } finally {
192 directoryContactsCursor.close();
Scott Kennedy94fa3012013-02-15 18:22:05 -0800193 }
mindyp16923ee2012-12-10 11:58:29 -0800194 }
195 }
196 }
197 }
Scott Kennedy94fa3012013-02-15 18:22:05 -0800198
Alon Albert76f1f2d2013-07-14 15:32:49 +0300199 // If no matches found in contact provider or the directories, try the extension
200 // matcher.
201 // todo (aalbert): This whole method needs to be in the adapter?
202 if (adapter != null) {
203 final Map<String, RecipientEntry> entries =
204 adapter.getMatchingRecipients(matchesNotFound);
205 if (entries != null && entries.size() > 0) {
206 callback.matchesFound(entries);
207 for (final String address : entries.keySet()) {
208 matchesNotFound.remove(address);
209 }
210 }
211 }
Scott Kennedy94fa3012013-02-15 18:22:05 -0800212 callback.matchesNotFound(matchesNotFound);
mindyp16923ee2012-12-10 11:58:29 -0800213 }
214
215 private static HashMap<String, RecipientEntry> processContactEntries(Cursor c) {
216 HashMap<String, RecipientEntry> recipientEntries = new HashMap<String, RecipientEntry>();
217 if (c != null && c.moveToFirst()) {
218 do {
219 String address = c.getString(Queries.Query.DESTINATION);
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800220
221 final RecipientEntry newRecipientEntry = RecipientEntry.constructTopLevelEntry(
mindyp16923ee2012-12-10 11:58:29 -0800222 c.getString(Queries.Query.NAME),
223 c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
224 c.getString(Queries.Query.DESTINATION),
225 c.getInt(Queries.Query.DESTINATION_TYPE),
226 c.getString(Queries.Query.DESTINATION_LABEL),
227 c.getLong(Queries.Query.CONTACT_ID),
228 c.getLong(Queries.Query.DATA_ID),
229 c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
Scott Kennedy514f8a72013-11-13 15:58:08 -0800230 true,
231 false /* isGalContact TODO(skennedy) We should look these up eventually */);
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800232
233 /*
234 * In certain situations, we may have two results for one address, where one of the
235 * results is just the email address, and the other has a name and photo, so we want
236 * to use the better one.
237 */
238 final RecipientEntry recipientEntry =
239 getBetterRecipient(recipientEntries.get(address), newRecipientEntry);
240
241 recipientEntries.put(address, recipientEntry);
mindyp16923ee2012-12-10 11:58:29 -0800242 if (Log.isLoggable(TAG, Log.DEBUG)) {
243 Log.d(TAG, "Received reverse look up information for " + address
244 + " RESULTS: "
245 + " NAME : " + c.getString(Queries.Query.NAME)
246 + " CONTACT ID : " + c.getLong(Queries.Query.CONTACT_ID)
247 + " ADDRESS :" + c.getString(Queries.Query.DESTINATION));
248 }
249 } while (c.moveToNext());
250 }
Mindy Pereira18529312011-06-28 11:00:52 -0700251 return recipientEntries;
252 }
253
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800254 /**
255 * Given two {@link RecipientEntry}s for the same email address, this will return the one that
256 * contains more complete information for display purposes. Defaults to <code>entry2</code> if
257 * no significant differences are found.
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800258 */
Scott Kennedy78f38a02013-02-27 11:21:40 -0800259 static RecipientEntry getBetterRecipient(final RecipientEntry entry1,
Scott Kennedyef3f76c2013-02-25 10:48:25 -0800260 final RecipientEntry entry2) {
261 // If only one has passed in, use it
262 if (entry2 == null) {
263 return entry1;
264 }
265
266 if (entry1 == null) {
267 return entry2;
268 }
269
270 // If only one has a display name, use it
271 if (!TextUtils.isEmpty(entry1.getDisplayName())
272 && TextUtils.isEmpty(entry2.getDisplayName())) {
273 return entry1;
274 }
275
276 if (!TextUtils.isEmpty(entry2.getDisplayName())
277 && TextUtils.isEmpty(entry1.getDisplayName())) {
278 return entry2;
279 }
280
281 // If only one has a display name that is not the same as the destination, use it
282 if (!TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())
283 && TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())) {
284 return entry1;
285 }
286
287 if (!TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())
288 && TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())) {
289 return entry2;
290 }
291
292 // If only one has a photo, use it
293 if ((entry1.getPhotoThumbnailUri() != null || entry1.getPhotoBytes() != null)
294 && (entry2.getPhotoThumbnailUri() == null && entry2.getPhotoBytes() == null)) {
295 return entry1;
296 }
297
298 if ((entry2.getPhotoThumbnailUri() != null || entry2.getPhotoBytes() != null)
299 && (entry1.getPhotoThumbnailUri() == null && entry1.getPhotoBytes() == null)) {
300 return entry2;
301 }
302
303 // Go with the second option as a default
304 return entry2;
305 }
306
mindyp16923ee2012-12-10 11:58:29 -0800307 private static Cursor doQuery(CharSequence constraint, int limit, Long directoryId,
308 Account account, ContentResolver resolver, Query query) {
309 final Uri.Builder builder = query
310 .getContentFilterUri()
311 .buildUpon()
312 .appendPath(constraint.toString())
313 .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
314 String.valueOf(limit + BaseRecipientAdapter.ALLOWANCE_FOR_DUPLICATES));
315 if (directoryId != null) {
316 builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
317 String.valueOf(directoryId));
318 }
319 if (account != null) {
320 builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_NAME, account.name);
321 builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_TYPE, account.type);
322 }
323 final Cursor cursor = resolver.query(builder.build(), query.getProjection(), null, null,
324 null);
325 return cursor;
326 }
327
Scott Kennedyf7e202d2013-03-06 21:38:10 -0800328 public RecipientAlternatesAdapter(Context context, long contactId, long currentId,
Kevin Linb10d1c62014-01-24 12:45:00 -0800329 int queryMode, OnCheckedItemChangedListener listener,
330 DropdownChipLayouter dropdownChipLayouter) {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700331 super(context, getCursorForConstruction(context, contactId, queryMode), 0);
Mindy Pereira97d77682011-06-01 10:48:55 -0700332 mCurrentId = currentId;
Mindy Pereira50863912011-06-16 18:54:10 -0700333 mCheckedItemChangedListener = listener;
Tom Taylor80f4abf2012-04-06 13:37:20 -0700334
335 if (queryMode == QUERY_TYPE_EMAIL) {
336 mQuery = Queries.EMAIL;
337 } else if (queryMode == QUERY_TYPE_PHONE) {
338 mQuery = Queries.PHONE;
339 } else {
340 mQuery = Queries.EMAIL;
341 Log.e(TAG, "Unsupported query type: " + queryMode);
342 }
Kevin Linb10d1c62014-01-24 12:45:00 -0800343
344 mDropdownChipLayouter = dropdownChipLayouter;
Tom Taylor80f4abf2012-04-06 13:37:20 -0700345 }
346
347 private static Cursor getCursorForConstruction(Context context, long contactId, int queryType) {
Makoto Onukia5d37c82012-05-03 13:40:45 -0700348 final Cursor cursor;
Tom Taylor80f4abf2012-04-06 13:37:20 -0700349 if (queryType == QUERY_TYPE_EMAIL) {
Makoto Onukia5d37c82012-05-03 13:40:45 -0700350 cursor = context.getContentResolver().query(
Tom Taylor80f4abf2012-04-06 13:37:20 -0700351 Queries.EMAIL.getContentUri(),
352 Queries.EMAIL.getProjection(),
Mindy Pereiraa62ba492012-04-24 16:34:26 -0700353 Queries.EMAIL.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700354 String.valueOf(contactId)
355 }, null);
356 } else {
Makoto Onukia5d37c82012-05-03 13:40:45 -0700357 cursor = context.getContentResolver().query(
Tom Taylor80f4abf2012-04-06 13:37:20 -0700358 Queries.PHONE.getContentUri(),
359 Queries.PHONE.getProjection(),
Tom Taylor9c17ab52012-04-25 13:53:36 -0700360 Queries.PHONE.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700361 String.valueOf(contactId)
362 }, null);
363 }
Makoto Onukia5d37c82012-05-03 13:40:45 -0700364 return removeDuplicateDestinations(cursor);
365 }
366
367 /**
368 * @return a new cursor based on the given cursor with all duplicate destinations removed.
369 *
370 * It's only intended to use for the alternate list, so...
371 * - This method ignores all other fields and dedupe solely on the destination. Normally,
372 * if a cursor contains multiple contacts and they have the same destination, we'd still want
373 * to show both.
374 * - This method creates a MatrixCursor, so all data will be kept in memory. We wouldn't want
375 * to do this if the original cursor is large, but it's okay here because the alternate list
376 * won't be that big.
377 */
378 // Visible for testing
379 /* package */ static Cursor removeDuplicateDestinations(Cursor original) {
380 final MatrixCursor result = new MatrixCursor(
381 original.getColumnNames(), original.getCount());
382 final HashSet<String> destinationsSeen = new HashSet<String>();
383
384 original.moveToPosition(-1);
385 while (original.moveToNext()) {
386 final String destination = original.getString(Query.DESTINATION);
387 if (destinationsSeen.contains(destination)) {
388 continue;
389 }
390 destinationsSeen.add(destination);
391
392 result.addRow(new Object[] {
393 original.getString(Query.NAME),
394 original.getString(Query.DESTINATION),
395 original.getInt(Query.DESTINATION_TYPE),
396 original.getString(Query.DESTINATION_LABEL),
397 original.getLong(Query.CONTACT_ID),
398 original.getLong(Query.DATA_ID),
399 original.getString(Query.PHOTO_THUMBNAIL_URI),
400 original.getInt(Query.DISPLAY_NAME_SOURCE)
401 });
402 }
403
404 return result;
Mindy Pereira97d77682011-06-01 10:48:55 -0700405 }
406
407 @Override
408 public long getItemId(int position) {
409 Cursor c = getCursor();
Mindy Pereira3bb52162011-07-01 14:52:22 -0700410 if (c.moveToPosition(position)) {
Tom Taylor80f4abf2012-04-06 13:37:20 -0700411 c.getLong(Queries.Query.DATA_ID);
Mindy Pereira3bb52162011-07-01 14:52:22 -0700412 }
413 return -1;
Mindy Pereira97d77682011-06-01 10:48:55 -0700414 }
415
416 public RecipientEntry getRecipientEntry(int position) {
417 Cursor c = getCursor();
418 c.moveToPosition(position);
Tom Taylor80f4abf2012-04-06 13:37:20 -0700419 return RecipientEntry.constructTopLevelEntry(
420 c.getString(Queries.Query.NAME),
Makoto Onuki00adb322012-05-01 16:50:41 -0700421 c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
Tom Taylor80f4abf2012-04-06 13:37:20 -0700422 c.getString(Queries.Query.DESTINATION),
423 c.getInt(Queries.Query.DESTINATION_TYPE),
424 c.getString(Queries.Query.DESTINATION_LABEL),
425 c.getLong(Queries.Query.CONTACT_ID),
426 c.getLong(Queries.Query.DATA_ID),
mindypccb8e232012-11-14 11:59:27 -0800427 c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
Scott Kennedy514f8a72013-11-13 15:58:08 -0800428 true,
429 false /* isGalContact TODO(skennedy) We should look these up eventually */);
Mindy Pereira97d77682011-06-01 10:48:55 -0700430 }
431
432 @Override
433 public View getView(int position, View convertView, ViewGroup parent) {
Mindy Pereira67ad4892011-06-02 12:21:22 -0700434 Cursor cursor = getCursor();
435 cursor.moveToPosition(position);
Mindy Pereira97d77682011-06-01 10:48:55 -0700436 if (convertView == null) {
Kevin Linb10d1c62014-01-24 12:45:00 -0800437 convertView = mDropdownChipLayouter.newView();
Mindy Pereira007a76b2011-06-14 11:39:36 -0700438 }
Tom Taylor80f4abf2012-04-06 13:37:20 -0700439 if (cursor.getLong(Queries.Query.DATA_ID) == mCurrentId) {
Mindy Pereira007a76b2011-06-14 11:39:36 -0700440 mCheckedItemPosition = position;
Mindy Pereira50863912011-06-16 18:54:10 -0700441 if (mCheckedItemChangedListener != null) {
442 mCheckedItemChangedListener.onCheckedItemChanged(mCheckedItemPosition);
443 }
Mindy Pereira97d77682011-06-01 10:48:55 -0700444 }
Mindy Pereira67ad4892011-06-02 12:21:22 -0700445 bindView(convertView, convertView.getContext(), cursor);
Mindy Pereira97d77682011-06-01 10:48:55 -0700446 return convertView;
447 }
448
449 @Override
450 public void bindView(View view, Context context, Cursor cursor) {
Mindy Pereira67ad4892011-06-02 12:21:22 -0700451 int position = cursor.getPosition();
Mindy Pereira67ad4892011-06-02 12:21:22 -0700452 RecipientEntry entry = getRecipientEntry(position);
Daisuke Miyakawa102cf102011-07-21 08:48:27 -0700453
Kevin Linb10d1c62014-01-24 12:45:00 -0800454 mDropdownChipLayouter.bindView(view, null, entry, position,
455 AdapterType.RECIPIENT_ALTERNATES, null);
Mindy Pereira97d77682011-06-01 10:48:55 -0700456 }
457
458 @Override
459 public View newView(Context context, Cursor cursor, ViewGroup parent) {
Kevin Linb10d1c62014-01-24 12:45:00 -0800460 return mDropdownChipLayouter.newView();
Mindy Pereira007a76b2011-06-14 11:39:36 -0700461 }
462
Mindy Pereira50863912011-06-16 18:54:10 -0700463 /*package*/ static interface OnCheckedItemChangedListener {
464 public void onCheckedItemChanged(int position);
Mindy Pereira97d77682011-06-01 10:48:55 -0700465 }
466}