BaseRecipientAdapter.java revision cf9337aa4b2d844f4941d75832f52266c4fc3fa7
16ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa/* 26ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Copyright (C) 2011 The Android Open Source Project 36ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * 46ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Licensed under the Apache License, Version 2.0 (the "License"); 56ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * you may not use this file except in compliance with the License. 66ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * You may obtain a copy of the License at 76ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * 86ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * http://www.apache.org/licenses/LICENSE-2.0 96ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * 106ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Unless required by applicable law or agreed to in writing, software 116ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * distributed under the License is distributed on an "AS IS" BASIS, 126ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * See the License for the specific language governing permissions and 146ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * limitations under the License. 156ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 166ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 176ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawapackage com.android.ex.chips; 186ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 196ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.accounts.Account; 206ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.content.ContentResolver; 216ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.content.Context; 226ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.content.pm.PackageManager; 236ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.content.pm.PackageManager.NameNotFoundException; 246ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.content.res.Resources; 256ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.database.Cursor; 266ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.graphics.Bitmap; 276ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.graphics.BitmapFactory; 286ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.net.Uri; 296ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.os.Handler; 3074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawaimport android.os.HandlerThread; 316ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.provider.ContactsContract; 326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Email; 33d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Phone; 3474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Photo; 356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.provider.ContactsContract.Contacts; 366ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.provider.ContactsContract.Directory; 376ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.text.TextUtils; 386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.text.util.Rfc822Token; 396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.util.Log; 4074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawaimport android.util.LruCache; 41d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawaimport android.view.LayoutInflater; 426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.view.View; 436ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.view.ViewGroup; 446ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.AutoCompleteTextView; 456ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.BaseAdapter; 466ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.Filter; 476ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.Filterable; 486ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.ImageView; 496ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.TextView; 506ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 516ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport java.util.ArrayList; 5274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawaimport java.util.HashSet; 53cf9337aa4b2d844f4941d75832f52266c4fc3fa7Daisuke Miyakawaimport java.util.LinkedHashMap; 546ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport java.util.List; 556ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport java.util.Map; 5674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawaimport java.util.Set; 576ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 586ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa/** 596ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Adapter for showing a recipient list. 606ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 61efcac0cbb3efc645cd6cf1cb1e2431e1bd2b2d2aMindy Pereirapublic abstract class BaseRecipientAdapter extends BaseAdapter implements Filterable { 626ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private static final String TAG = "BaseRecipientAdapter"; 6374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private static final boolean DEBUG = false; 646ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 656ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 666ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * The preferred number of results to be retrieved. This number may be 676ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * exceeded if there are several directories configured, because we will use 686ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * the same limit for all directories. 696ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 706ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private static final int DEFAULT_PREFERRED_MAX_RESULT_COUNT = 10; 716ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 726ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 736ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * The number of extra entries requested to allow for duplicates. Duplicates 746ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * are removed from the overall result. 756ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 766ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private static final int ALLOWANCE_FOR_DUPLICATES = 5; 776ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 7874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa /** The number of photos cached in this Adapter. */ 7974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private static final int PHOTO_CACHE_SIZE = 20; 8074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 81d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public static final int QUERY_TYPE_EMAIL = 0; 82d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public static final int QUERY_TYPE_PHONE = 1; 83d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa 846ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 856ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Model object for a {@link Directory} row. 866ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 876ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public final static class DirectorySearchParams { 886ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public long directoryId; 896ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String directoryType; 906ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String displayName; 916ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String accountName; 926ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String accountType; 936ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public CharSequence constraint; 946ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public DirectoryFilter filter; 956ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 966ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 976ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private static class EmailQuery { 986ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final String[] PROJECTION = { 996ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Contacts.DISPLAY_NAME, // 0 1006ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Email.DATA, // 1 1016ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Email.CONTACT_ID, // 2 1026ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Contacts.PHOTO_THUMBNAIL_URI // 3 1036ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa }; 1046ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1056ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int NAME = 0; 1066ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int ADDRESS = 1; 1076ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int CONTACT_ID = 2; 1086ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int PHOTO_THUMBNAIL_URI = 3; 1096ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1106ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 111d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa private static class PhoneQuery { 112d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public static final String[] PROJECTION = { 113d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa Contacts.DISPLAY_NAME, // 0 114d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa Phone.DATA, // 1 115d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa Phone.CONTACT_ID, // 2 116d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa Contacts.PHOTO_THUMBNAIL_URI // 3 117d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa }; 118d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public static final int NAME = 0; 119d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public static final int NUMBER = 1; 120d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public static final int CONTACT_ID = 2; 121d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public static final int PHOTO_THUMBNAIL_URI = 3; 122d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 1236ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 12474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private static class PhotoQuery { 12574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public static final String[] PROJECTION = { 12674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa Photo.PHOTO 12774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa }; 12874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 12974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public static final int PHOTO = 0; 13074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 13174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 1326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private static class DirectoryListQuery { 1336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final Uri URI = 1356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "directories"); 1366ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final String[] PROJECTION = { 1376ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory._ID, // 0 1386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.ACCOUNT_NAME, // 1 1396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.ACCOUNT_TYPE, // 2 1406ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.DISPLAY_NAME, // 3 1416ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.PACKAGE_NAME, // 4 1426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.TYPE_RESOURCE_ID, // 5 1436ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa }; 1446ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1456ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int ID = 0; 1466ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int ACCOUNT_NAME = 1; 1476ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int ACCOUNT_TYPE = 2; 1486ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int DISPLAY_NAME = 3; 1496ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int PACKAGE_NAME = 4; 1506ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int TYPE_RESOURCE_ID = 5; 1516ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1526ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1536ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 1546ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * An asynchronous filter used for loading two data sets: email rows from the local 1556ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * contact provider and the list of {@link Directory}'s. 1566ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 1576ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private final class DefaultFilter extends Filter { 1586ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1596ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 1606ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected FilterResults performFiltering(CharSequence constraint) { 16174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final FilterResults results = new FilterResults(); 1626ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Cursor cursor = null; 1636ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (!TextUtils.isEmpty(constraint)) { 164d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa cursor = doQuery(constraint, mPreferredMaxResultCount, null); 1656ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (cursor != null) { 1666ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa results.count = cursor.getCount(); 1676ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1686ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1696ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1706ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // TODO: implement group feature 1716ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1726ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final Cursor directoryCursor = mContentResolver.query( 1736ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa DirectoryListQuery.URI, DirectoryListQuery.PROJECTION, null, null, null); 1746ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 17574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (DEBUG && cursor == null) { 17674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa Log.w(TAG, "null cursor returned for default Email filter query."); 17774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 1786ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa results.values = new Cursor[] { directoryCursor, cursor }; 1796ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return results; 1806ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1816ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1826ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 1836ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected void publishResults(final CharSequence constraint, FilterResults results) { 1846ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (results.values != null) { 1856ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final Cursor[] cursors = (Cursor[]) results.values; 1866ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // Run on one thread. 1876ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mHandler.post(new Runnable() { 1886ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 1896ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public void run() { 1906ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa onFirstDirectoryLoadFinished(constraint, cursors[0], cursors[1]); 1916ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1926ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa }); 1936ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1946ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa results.count = getCount(); 1956ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1966ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1976ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 1986ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public CharSequence convertResultToString(Object resultValue) { 1996ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final RecipientListEntry entry = (RecipientListEntry)resultValue; 2006ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final String displayName = entry.getDisplayName(); 2016ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final String emailAddress = entry.getDestination(); 2026ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, emailAddress)) { 2036ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return emailAddress; 2046ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } else { 2056ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return new Rfc822Token(displayName, emailAddress, null).toString(); 2066ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2076ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2086ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2096ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2106ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 2116ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * An asynchronous filter that performs search in a particular directory. 2126ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 2136ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private final class DirectoryFilter extends Filter { 21474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final DirectorySearchParams mParams; 2156ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private int mLimit; 2166ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 21774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public DirectoryFilter(DirectorySearchParams params) { 21874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa this.mParams = params; 2196ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2206ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2216ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public synchronized void setLimit(int limit) { 2226ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa this.mLimit = limit; 2236ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2246ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2256ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public synchronized int getLimit() { 2266ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return this.mLimit; 2276ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2286ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2296ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 2306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected FilterResults performFiltering(CharSequence constraint) { 23174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final FilterResults results = new FilterResults(); 2326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (!TextUtils.isEmpty(constraint)) { 233d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final Cursor cursor = doQuery(constraint, getLimit(), mParams.directoryId); 23474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (cursor != null) { 23574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa results.values = cursor; 23674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 2376ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // TODO: implement group feature 2406ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2416ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return results; 2426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2436ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2446ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 2456ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected void publishResults(final CharSequence constraint, FilterResults results) { 2466ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final Cursor cursor = (Cursor) results.values; 2476ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mHandler.post(new Runnable() { 2486ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 2496ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public void run() { 25074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa onDirectoryLoadFinished(constraint, mParams, cursor); 2516ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2526ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa }); 2536ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa results.count = getCount(); 2546ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2556ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2566ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 25774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final Context mContext; 2586ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private final ContentResolver mContentResolver; 259d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa private final LayoutInflater mInflater; 260d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa private final int mQueryType; 2616ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private Account mAccount; 26274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final int mPreferredMaxResultCount; 2636ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private final Handler mHandler = new Handler(); 2646ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2656ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 26674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * Each destination (an email address or a phone number) with a valid contactId is first 26774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * inserted into {@link #mEntryMap} and grouped by the contactId. 26874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * Destinations without valid contactId (possible if they aren't in local storage) are stored 26974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * in {@link #mNonAggregatedEntries}. 27074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * Duplicates are removed using {@link #mExistingDestinations}. 27174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * 27274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * After having all results from ContentResolver, all elements in mEntryMap are copied to 27374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * mEntry, which will be used to find items in this Adapter. If the number of contacts in 27474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * mEntries are less than mPreferredMaxResultCount, contacts in 27574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * mNonAggregatedEntries are also used. 2766ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 277cf9337aa4b2d844f4941d75832f52266c4fc3fa7Daisuke Miyakawa private final LinkedHashMap<Integer, List<RecipientListEntry>> mEntryMap; 27874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final List<RecipientListEntry> mNonAggregatedEntries; 27974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final List<RecipientListEntry> mEntries; 28074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final Set<String> mExistingDestinations; 2816ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 28274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa /** 28374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * Used to ignore asynchronous queries with a different constraint, which may appear when 28474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * users type characters quickly. 28574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa */ 28674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private CharSequence mCurrentConstraint; 28774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 28874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final HandlerThread mPhotoHandlerThread; 28974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final Handler mPhotoHandler; 29074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final LruCache<Uri, byte[]> mPhotoCacheMap; 2916ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 292d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa /** 293d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * Constructor for email queries. 294d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa */ 2956ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public BaseRecipientAdapter(Context context) { 296d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa this(context, QUERY_TYPE_EMAIL, DEFAULT_PREFERRED_MAX_RESULT_COUNT); 297d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 298d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa 299d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public BaseRecipientAdapter(Context context, int queryType) { 300d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa this(context, queryType, DEFAULT_PREFERRED_MAX_RESULT_COUNT); 3016ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3026ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 303d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public BaseRecipientAdapter(Context context, int queryType, int preferredMaxResultCount) { 3046ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mContext = context; 3056ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mContentResolver = context.getContentResolver(); 306d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa mInflater = LayoutInflater.from(context); 307d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa mQueryType = queryType; 3086ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mPreferredMaxResultCount = preferredMaxResultCount; 309cf9337aa4b2d844f4941d75832f52266c4fc3fa7Daisuke Miyakawa mEntryMap = new LinkedHashMap<Integer, List<RecipientListEntry>>(); 31074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mNonAggregatedEntries = new ArrayList<RecipientListEntry>(); 31174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mEntries = new ArrayList<RecipientListEntry>(); 31274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mExistingDestinations = new HashSet<String>(); 31374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mPhotoHandlerThread = new HandlerThread("photo_handler"); 31474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mPhotoHandlerThread.start(); 31574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mPhotoHandler = new Handler(mPhotoHandlerThread.getLooper()); 31674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mPhotoCacheMap = new LruCache<Uri, byte[]>(PHOTO_CACHE_SIZE); 3176ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3186ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3196ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 3206ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Set the account when known. Causes the search to prioritize contacts from that account. 3216ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 3226ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public void setAccount(Account account) { 3236ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mAccount = account; 3246ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3256ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3266ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** Will be called from {@link AutoCompleteTextView} to prepare auto-complete list. */ 3276ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 3286ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public Filter getFilter() { 3296ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return new DefaultFilter(); 3306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3316ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 3336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Handles the result of the initial call, which brings back the list of directories as well 3346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * as the search results for the local directories. 33574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * 33674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * Must be inside a default Looper thread to avoid synchronization problem. 3376ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 3386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected void onFirstDirectoryLoadFinished( 3396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa CharSequence constraint, Cursor directoryCursor, Cursor defaultDirectoryCursor) { 34074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mCurrentConstraint = constraint; 34174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 3426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa try { 34374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final List<DirectorySearchParams> paramsList; 3446ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (directoryCursor != null) { 34574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa paramsList = setupOtherDirectories(directoryCursor); 34674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } else { 34774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa paramsList = null; 3486ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3496ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3506ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa int limit = 0; 3516ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 35274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (defaultDirectoryCursor != null) { 3536ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mEntryMap.clear(); 35474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mNonAggregatedEntries.clear(); 35574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mExistingDestinations.clear(); 35674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa putEntriesWithCursor(defaultDirectoryCursor, true); 3576ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa constructEntryList(); 3586ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa limit = mPreferredMaxResultCount - getCount(); 3596ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3606ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 36174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (limit > 0 && paramsList != null) { 36274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa searchOtherDirectories(constraint, paramsList, limit); 3636ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3646ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } finally { 3656ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (directoryCursor != null) { 3666ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa directoryCursor.close(); 3676ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3686ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (defaultDirectoryCursor != null) { 3696ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa defaultDirectoryCursor.close(); 3706ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3716ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3726ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3736ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 37474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private List<DirectorySearchParams> setupOtherDirectories(Cursor directoryCursor) { 3756ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final PackageManager packageManager = mContext.getPackageManager(); 37674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final List<DirectorySearchParams> paramsList = new ArrayList<DirectorySearchParams>(); 3776ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa DirectorySearchParams preferredDirectory = null; 3786ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa while (directoryCursor.moveToNext()) { 3796ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final long id = directoryCursor.getLong(DirectoryListQuery.ID); 3806ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3816ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // Skip the local invisible directory, because the default directory already includes 3826ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // all local results. 3836ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (id == Directory.LOCAL_INVISIBLE) { 3846ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa continue; 3856ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3866ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3876ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final DirectorySearchParams params = new DirectorySearchParams(); 3886ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final String packageName = directoryCursor.getString(DirectoryListQuery.PACKAGE_NAME); 3896ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final int resourceId = directoryCursor.getInt(DirectoryListQuery.TYPE_RESOURCE_ID); 3906ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.directoryId = id; 3916ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.displayName = directoryCursor.getString(DirectoryListQuery.DISPLAY_NAME); 3926ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.accountName = directoryCursor.getString(DirectoryListQuery.ACCOUNT_NAME); 3936ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.accountType = directoryCursor.getString(DirectoryListQuery.ACCOUNT_TYPE); 3946ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (packageName != null && resourceId != 0) { 3956ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa try { 3966ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final Resources resources = 3976ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa packageManager.getResourcesForApplication(packageName); 3986ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.directoryType = resources.getString(resourceId); 3996ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (params.directoryType == null) { 4006ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Log.e(TAG, "Cannot resolve directory name: " 4016ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa + resourceId + "@" + packageName); 4026ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4036ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } catch (NameNotFoundException e) { 4046ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Log.e(TAG, "Cannot resolve directory name: " 4056ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa + resourceId + "@" + packageName, e); 4066ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4076ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4086ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 4096ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // If an account has been provided and we found a directory that 4106ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // corresponds to that account, place that directory second, directly 4116ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // underneath the local contacts. 4126ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (mAccount != null && mAccount.name.equals(params.accountName) && 4136ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mAccount.type.equals(params.accountType)) { 4146ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa preferredDirectory = params; 4156ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } else { 41674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa paramsList.add(params); 4176ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4186ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4196ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 4206ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (preferredDirectory != null) { 42174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa paramsList.add(1, preferredDirectory); 4226ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4236ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 42474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa return paramsList; 4256ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4266ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 4276ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 4286ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Starts search in other directories 4296ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 43074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private void searchOtherDirectories( 43174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa CharSequence constraint, List<DirectorySearchParams> paramsList, int limit) { 43274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final int count = paramsList.size(); 4336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // Note: skipping the default partition (index 0), which has already been loaded 4346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa for (int i = 1; i < count; i++) { 43574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final DirectorySearchParams params = paramsList.get(i); 43674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.constraint = constraint; 43774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (params.filter == null) { 43874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.filter = new DirectoryFilter(params); 43974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 44074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.filter.setLimit(limit); 44174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.filter.filter(constraint); 44274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 44374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 44474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 44574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa /** Must be inside a default Looper thread to avoid synchronization problem. */ 44674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public void onDirectoryLoadFinished( 44774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa CharSequence constraint, DirectorySearchParams params, Cursor cursor) { 44874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (cursor != null) { 44974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa try { 45074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (DEBUG) { 45174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa Log.v(TAG, "finished loading directory \"" + params.displayName + "\"" + 45274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa " with query " + constraint); 45374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 45474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 45574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa // Check if the received result matches the current constraint 45674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa // If not - the user must have continued typing after the request was issued 45774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final boolean usesSameConstraint; 45874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa usesSameConstraint = TextUtils.equals(constraint, mCurrentConstraint); 45974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (usesSameConstraint) { 46074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa putEntriesWithCursor(cursor, params.directoryId == Directory.DEFAULT); 46174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa constructEntryList(); 46274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 46374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } finally { 46474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa cursor.close(); 4656ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4666ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4676ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4686ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 4696ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 4706ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Stores each contact information to {@link #mEntryMap}. {@link #mEntries} isn't touched here. 4716ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * 4726ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * In order to make the new information available from outside Adapter, 4736ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * call {@link #constructEntryList()} after this method. 4746ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 47574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private void putEntriesWithCursor(Cursor cursor, boolean validContactId) { 4766ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa cursor.move(-1); 4776ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa while (cursor.moveToNext()) { 478d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final String displayName; 479d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final String destination; 480d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final int contactId; 481d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final String thumbnailUriString; 482d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa if (mQueryType == QUERY_TYPE_EMAIL) { 483d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa displayName = cursor.getString(EmailQuery.NAME); 484d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa destination = cursor.getString(EmailQuery.ADDRESS); 485d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa contactId = cursor.getInt(EmailQuery.CONTACT_ID); 486d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa thumbnailUriString = cursor.getString(EmailQuery.PHOTO_THUMBNAIL_URI); 487d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } else if (mQueryType == QUERY_TYPE_PHONE) { 488d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa displayName = cursor.getString(PhoneQuery.NAME); 489d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa destination = cursor.getString(PhoneQuery.NUMBER); 490d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa contactId = cursor.getInt(PhoneQuery.CONTACT_ID); 491d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa thumbnailUriString = cursor.getString(PhoneQuery.PHOTO_THUMBNAIL_URI); 492d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } else { 493d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa throw new IndexOutOfBoundsException("Unexpected query type: " + mQueryType); 494d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 49574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 49674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa // Note: At this point each entry doesn't contain have any photo (thus getPhotoBytes() 49774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa // returns null). 49874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 49974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (mExistingDestinations.contains(destination)) { 50074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa continue; 50174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 50274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mExistingDestinations.add(destination); 5036ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 50474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (!validContactId) { 50574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mNonAggregatedEntries.add(RecipientListEntry.constructTopLevelEntry( 50674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa displayName, destination, contactId, thumbnailUriString)); 50774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } else if (mEntryMap.containsKey(contactId)) { 5086ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // We already have a section for the person. 5096ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final List<RecipientListEntry> entryList = mEntryMap.get(contactId); 51074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa entryList.add(RecipientListEntry.constructSecondLevelEntry( 51174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa displayName, destination, contactId)); 5126ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } else { 5136ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final List<RecipientListEntry> entryList = new ArrayList<RecipientListEntry>(); 5146ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa entryList.add(RecipientListEntry.constructTopLevelEntry( 51574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa displayName, destination, contactId, thumbnailUriString)); 5166ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mEntryMap.put(contactId, entryList); 5176ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5186ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5196ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5206ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 5216ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 52274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * Constructs an actual list for this Adapter using {@link #mEntryMap}. Also tries to 52374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * fetch a cached photo for each contact entry (other than separators), or request another 52474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * thread to get one from directories. The thread ({@link #mPhotoHandlerThread}) will 52574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * request {@link #notifyDataSetChanged()} after having the photo asynchronously. 5266ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 5276ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private void constructEntryList() { 52874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mEntries.clear(); 52974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa int validEntryCount = 0; 5306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa for (Map.Entry<Integer, List<RecipientListEntry>> mapEntry : mEntryMap.entrySet()) { 5316ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final List<RecipientListEntry> entryList = mapEntry.getValue(); 5326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final int size = entryList.size(); 5336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa for (int i = 0; i < size; i++) { 5346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa RecipientListEntry entry = entryList.get(i); 5356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mEntries.add(entry); 53674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa tryFetchPhoto(entry); 53774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa validEntryCount++; 5386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (i < size - 1) { 5396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mEntries.add(RecipientListEntry.SEP_WITHIN_GROUP); 5406ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5416ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mEntries.add(RecipientListEntry.SEP_NORMAL); 54374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (validEntryCount > mPreferredMaxResultCount) { 54474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa break; 54574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 5466ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 54774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (validEntryCount <= mPreferredMaxResultCount) { 54874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa for (RecipientListEntry entry : mNonAggregatedEntries) { 54974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (validEntryCount > mPreferredMaxResultCount) { 55074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa break; 55174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 55274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mEntries.add(entry); 55374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa tryFetchPhoto(entry); 55474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 55574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mEntries.add(RecipientListEntry.SEP_NORMAL); 55674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa validEntryCount++; 55774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 55874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 55974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 56074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa // Remove last divider 5616ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (mEntries.size() > 1) { 5626ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mEntries.remove(mEntries.size() - 1); 5636ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5646ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa notifyDataSetChanged(); 5656ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5666ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 56774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private void tryFetchPhoto(final RecipientListEntry entry) { 56874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final Uri photoThumbnailUri = entry.getPhotoThumbnailUri(); 56974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (photoThumbnailUri != null) { 57074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final byte[] photoBytes = mPhotoCacheMap.get(photoThumbnailUri); 57174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (photoBytes != null) { 57274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa entry.setPhotoBytes(photoBytes); 57374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa // notifyDataSetChanged() should be called by a caller. 57474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } else { 57574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (DEBUG) { 57674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa Log.d(TAG, "No photo cache for " + entry.getDisplayName() 57774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa + ". Fetch one asynchronously"); 5786ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 57974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa fetchPhotoAsync(entry, photoThumbnailUri); 5806ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5816ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5826ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5836ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 58474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private void fetchPhotoAsync(final RecipientListEntry entry, final Uri photoThumbnailUri) { 58574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mPhotoHandler.post(new Runnable() { 58674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa @Override 58774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public void run() { 58874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final Cursor photoCursor = mContentResolver.query( 58974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa photoThumbnailUri, PhotoQuery.PROJECTION, null, null, null); 59074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (photoCursor != null) { 59174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa try { 59274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (photoCursor.moveToFirst()) { 59374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final byte[] photoBytes = photoCursor.getBlob(PhotoQuery.PHOTO); 59474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa entry.setPhotoBytes(photoBytes); 59574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 59674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mHandler.post(new Runnable() { 59774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa @Override 59874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public void run() { 59974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mPhotoCacheMap.put(photoThumbnailUri, photoBytes); 60074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa notifyDataSetChanged(); 60174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 60274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa }); 60374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 60474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } finally { 60574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa photoCursor.close(); 60674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 60774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 60874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 60974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa }); 61074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 61174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 612d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa private Cursor doQuery(CharSequence constraint, int limit, Long directoryId) { 613d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final Cursor cursor; 614d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa if (mQueryType == QUERY_TYPE_EMAIL) { 615d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final Uri.Builder builder = Email.CONTENT_FILTER_URI.buildUpon() 616d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa .appendPath(constraint.toString()) 617d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, 618d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa String.valueOf(limit + ALLOWANCE_FOR_DUPLICATES)); 619d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa if (directoryId != null) { 620d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 621d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa String.valueOf(directoryId)); 622d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 623d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa cursor = mContentResolver.query( 624d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa builder.build(), EmailQuery.PROJECTION, null, null, null); 625d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } else if (mQueryType == QUERY_TYPE_PHONE){ 626d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final Uri.Builder builder = Phone.CONTENT_FILTER_URI.buildUpon() 627d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa .appendPath(constraint.toString()) 628d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, 629d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa String.valueOf(limit + ALLOWANCE_FOR_DUPLICATES)); 630d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa if (directoryId != null) { 631d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 632d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa String.valueOf(directoryId)); 633d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 634d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa cursor = mContentResolver.query( 635d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa builder.build(), PhoneQuery.PROJECTION, null, null, null); 636d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } else { 637d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa cursor = null; 638d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 639d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa return cursor; 640d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 641d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa 6426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public void close() { 64374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mEntryMap.clear(); 64474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mNonAggregatedEntries.clear(); 64574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mExistingDestinations.clear(); 64674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mEntries.clear(); 64774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mPhotoCacheMap.evictAll(); 64874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (!mPhotoHandlerThread.quit()) { 64974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa Log.w(TAG, "Failed to quit photo handler thread, ignoring it."); 65074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 6516ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6526ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6536ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 6546ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public int getCount() { 65574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa return mEntries.size(); 6566ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6576ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6586ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 6596ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public Object getItem(int position) { 66074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa return mEntries.get(position); 6616ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6626ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6636ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 6646ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public long getItemId(int position) { 6656ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return position; 6666ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6676ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6686ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 66974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public int getViewTypeCount() { 67074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa return RecipientListEntry.ENTRY_TYPE_SIZE; 67174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 67274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 67374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa @Override 67474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public int getItemViewType(int position) { 67574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa return mEntries.get(position).getEntryType(); 67674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 6776ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 67874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa @Override 67974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public View getView(int position, View convertView, ViewGroup parent) { 6806ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final RecipientListEntry entry = mEntries.get(position); 68174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa switch (entry.getEntryType()) { 68274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa case RecipientListEntry.ENTRY_TYPE_SEP_NORMAL: { 683d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa return convertView != null ? convertView 684d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa : mInflater.inflate(getSeparatorLayout(), parent, false); 6856ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 68674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa case RecipientListEntry.ENTRY_TYPE_SEP_WITHIN_GROUP: { 68774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa return convertView != null ? convertView 688d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa : mInflater.inflate(getSeparatorWithinGroupLayout(), parent, false); 6896ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 69074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa default: { 69174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa String displayName = entry.getDisplayName(); 69274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa String emailAddress = entry.getDestination(); 69374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (TextUtils.isEmpty(displayName) 69474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa || TextUtils.equals(displayName, emailAddress)) { 69574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa displayName = emailAddress; 69674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa emailAddress = null; 69774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 6986ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 699d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final View itemView = convertView != null ? convertView 700d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa : mInflater.inflate(getItemLayout(), parent, false); 701d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final TextView displayNameView = 702d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa (TextView)itemView.findViewById(getDisplayNameId()); 703d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final TextView emailAddressView = 704d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa (TextView)itemView.findViewById(getDestinationId()); 705d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa final ImageView imageView = (ImageView)itemView.findViewById(getPhotoId()); 70674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa displayNameView.setText(displayName); 70774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (!TextUtils.isEmpty(emailAddress)) { 70874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa emailAddressView.setText(emailAddress); 70974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 7106ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (entry.isFirstLevel()) { 71174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa displayNameView.setVisibility(View.VISIBLE); 71274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (imageView != null) { 713d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa imageView.setVisibility(View.VISIBLE); 71474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final byte[] photoBytes = entry.getPhotoBytes(); 71574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (photoBytes != null && imageView != null) { 71674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final Bitmap photo = BitmapFactory.decodeByteArray( 71774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa photoBytes, 0, photoBytes.length); 71874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa imageView.setImageBitmap(photo); 71974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } else { 72074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa imageView.setImageResource(getDefaultPhotoResource()); 72174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 7226ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 7236ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } else { 7246ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa displayNameView.setVisibility(View.GONE); 725d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa if (imageView != null) imageView.setVisibility(View.GONE); 7266ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 72774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa return itemView; 7286ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 7296ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 7306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 7316ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 7326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 733d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * Returns a layout id for each item inside auto-complete list. 734d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * 735d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * Each View must contain two TextViews (for display name and destination) and one ImageView 736d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * (for photo). Ids for those should be available via {@link #getDisplayNameId()}, 737d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * {@link #getDestinationId()}, and {@link #getPhotoId()}. 7386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 739efcac0cbb3efc645cd6cf1cb1e2431e1bd2b2d2aMindy Pereira protected abstract int getItemLayout(); 740d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa /** Returns a layout id for a separator dividing two person or groups. */ 741efcac0cbb3efc645cd6cf1cb1e2431e1bd2b2d2aMindy Pereira protected abstract int getSeparatorLayout(); 7426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 743d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * Returns a layout id for a separator dividing two destinations for a same person or group. 7446ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 745efcac0cbb3efc645cd6cf1cb1e2431e1bd2b2d2aMindy Pereira protected abstract int getSeparatorWithinGroupLayout(); 7466ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 7476ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 7486ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Returns a resource ID representing an image which should be shown when ther's no relevant 7496ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * photo is available. 7506ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 751efcac0cbb3efc645cd6cf1cb1e2431e1bd2b2d2aMindy Pereira protected abstract int getDefaultPhotoResource(); 752d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa 753d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa /** 754d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * Returns an id for TextView in an item View for showing a display name. In default 755d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * {@link android.R.id#text1} is returned. 756d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa */ 757d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa protected int getDisplayNameId() { 758d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa return android.R.id.text1; 759d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 760d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa 761d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa /** 762d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * Returns an id for TextView in an item View for showing a destination 763d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * (an email address or a phone number). 764d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * In default {@link android.R.id#text2} is returned. 765d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa */ 766d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa protected int getDestinationId() { 767d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa return android.R.id.text2; 768d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 769d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa 770d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa /** 771d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * Returns an id for ImageView in an item View for showing photo image for a person. In default 772d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * {@link android.R.id#icon} is returned. 773d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa */ 774d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa protected int getPhotoId() { 775d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa return android.R.id.icon; 776d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 7776ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa} 778