BaseRecipientAdapter.java revision a601adc796fa7276771e6ab2670bf50663555489
141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa/* 241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * Copyright (C) 2011 The Android Open Source Project 341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * 441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * Licensed under the Apache License, Version 2.0 (the "License"); 541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * you may not use this file except in compliance with the License. 641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * You may obtain a copy of the License at 741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * 841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * http://www.apache.org/licenses/LICENSE-2.0 941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * 1041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * Unless required by applicable law or agreed to in writing, software 1141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * distributed under the License is distributed on an "AS IS" BASIS, 1241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * See the License for the specific language governing permissions and 1441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * limitations under the License. 1541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 1641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 1741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawapackage com.android.ex.chips; 1841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 1941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.accounts.Account; 2041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.content.ContentResolver; 2141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.content.Context; 2241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.content.pm.PackageManager; 2341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.content.pm.PackageManager.NameNotFoundException; 2441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.content.res.Resources; 2541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.database.Cursor; 2641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.graphics.Bitmap; 2741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.graphics.BitmapFactory; 2841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.net.Uri; 2941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.os.Handler; 3024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawaimport android.os.HandlerThread; 31a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawaimport android.os.Message; 3241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.provider.ContactsContract; 3341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Email; 34ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Phone; 3524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Photo; 3641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.provider.ContactsContract.Contacts; 3741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.provider.ContactsContract.Directory; 3841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.text.TextUtils; 3941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.text.util.Rfc822Token; 4041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.util.Log; 4124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawaimport android.util.LruCache; 42ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawaimport android.view.LayoutInflater; 4341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.view.View; 4441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.view.ViewGroup; 4541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.widget.AutoCompleteTextView; 4641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.widget.BaseAdapter; 4741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.widget.Filter; 4841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.widget.Filterable; 4941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.widget.ImageView; 5041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport android.widget.TextView; 5141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 5241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport java.util.ArrayList; 5324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawaimport java.util.HashSet; 54e3a582cc9b204f3f4150f81ec54da9872b3577a9Daisuke Miyakawaimport java.util.LinkedHashMap; 5541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport java.util.List; 5641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawaimport java.util.Map; 5724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawaimport java.util.Set; 5841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 5941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa/** 6041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * Adapter for showing a recipient list. 6141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 627a424984849627457aa27ac19c0d23cbe0887c85Mindy Pereirapublic abstract class BaseRecipientAdapter extends BaseAdapter implements Filterable, 6335654303c707e4b4926263c18090c58dca06f3a2Mindy Pereira AccountSpecifier { 6441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa private static final String TAG = "BaseRecipientAdapter"; 6524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private static final boolean DEBUG = false; 6641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 6741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 6841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * The preferred number of results to be retrieved. This number may be 6941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * exceeded if there are several directories configured, because we will use 7041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * the same limit for all directories. 7141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 7241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa private static final int DEFAULT_PREFERRED_MAX_RESULT_COUNT = 10; 7341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 7441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 7541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * The number of extra entries requested to allow for duplicates. Duplicates 7641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * are removed from the overall result. 7741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 7841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa private static final int ALLOWANCE_FOR_DUPLICATES = 5; 7941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 80b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa // This is ContactsContract.PRIMARY_ACCOUNT_NAME. Available from ICS as hidden 81b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa private static final String PRIMARY_ACCOUNT_NAME = "name_for_primary_account"; 82b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa // This is ContactsContract.PRIMARY_ACCOUNT_TYPE. Available from ICS as hidden 83b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa private static final String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account"; 84b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa 8524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa /** The number of photos cached in this Adapter. */ 8624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private static final int PHOTO_CACHE_SIZE = 20; 8724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 88a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa /** 89a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa * The "Waiting for more contacts" message will be displayed if search is not complete 90a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa * within this many milliseconds. 91a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa */ 92a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa private static final int MESSAGE_SEARCH_PENDING_DELAY = 1000; 93a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa /** Used to prepare "Waiting for more contacts" message. */ 94a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa private static final int MESSAGE_SEARCH_PENDING = 1; 95a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 96ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa public static final int QUERY_TYPE_EMAIL = 0; 97ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa public static final int QUERY_TYPE_PHONE = 1; 98ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa 9941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 10041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * Model object for a {@link Directory} row. 10141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 10241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public final static class DirectorySearchParams { 10341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public long directoryId; 10441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public String directoryType; 10541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public String displayName; 10641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public String accountName; 10741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public String accountType; 10841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public CharSequence constraint; 10941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public DirectoryFilter filter; 11041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 11141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 1125f2cc770801133c2db389ebe108063427d1cf6aaMindy Pereira /* package */ static class EmailQuery { 11341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final String[] PROJECTION = { 11441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Contacts.DISPLAY_NAME, // 0 11541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Email.DATA, // 1 11641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Email.CONTACT_ID, // 2 117b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa Email._ID, // 3 118b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa Contacts.PHOTO_THUMBNAIL_URI // 4 11941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa }; 12041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 12141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final int NAME = 0; 12241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final int ADDRESS = 1; 12341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final int CONTACT_ID = 2; 124b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa public static final int DATA_ID = 3; 125b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa public static final int PHOTO_THUMBNAIL_URI = 4; 12641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 12741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 128ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa private static class PhoneQuery { 129ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa public static final String[] PROJECTION = { 130ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa Contacts.DISPLAY_NAME, // 0 131ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa Phone.DATA, // 1 132ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa Phone.CONTACT_ID, // 2 133b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa Phone._ID, // 3 134b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa Contacts.PHOTO_THUMBNAIL_URI // 4 135ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa }; 136ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa public static final int NAME = 0; 137ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa public static final int NUMBER = 1; 138ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa public static final int CONTACT_ID = 2; 139b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa public static final int DATA_ID = 3; 140ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa public static final int PHOTO_THUMBNAIL_URI = 3; 141ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } 14241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 14324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private static class PhotoQuery { 14424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa public static final String[] PROJECTION = { 14524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa Photo.PHOTO 14624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa }; 14724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 14824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa public static final int PHOTO = 0; 14924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 15024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 15141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa private static class DirectoryListQuery { 15241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 15341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final Uri URI = 15441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "directories"); 15541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final String[] PROJECTION = { 15641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Directory._ID, // 0 15741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Directory.ACCOUNT_NAME, // 1 15841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Directory.ACCOUNT_TYPE, // 2 15941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Directory.DISPLAY_NAME, // 3 16041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Directory.PACKAGE_NAME, // 4 16141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Directory.TYPE_RESOURCE_ID, // 5 16241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa }; 16341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 16441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final int ID = 0; 16541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final int ACCOUNT_NAME = 1; 16641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final int ACCOUNT_TYPE = 2; 16741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final int DISPLAY_NAME = 3; 16841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final int PACKAGE_NAME = 4; 16941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public static final int TYPE_RESOURCE_ID = 5; 17041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 17141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 17241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 17341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * An asynchronous filter used for loading two data sets: email rows from the local 17441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * contact provider and the list of {@link Directory}'s. 17541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 17641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa private final class DefaultFilter extends Filter { 17741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 17841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa @Override 17941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa protected FilterResults performFiltering(CharSequence constraint) { 18024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final FilterResults results = new FilterResults(); 18141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Cursor cursor = null; 18241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (!TextUtils.isEmpty(constraint)) { 183ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa cursor = doQuery(constraint, mPreferredMaxResultCount, null); 18441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (cursor != null) { 18541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa results.count = cursor.getCount(); 18641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 18741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 18841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 18941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final Cursor directoryCursor = mContentResolver.query( 19041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa DirectoryListQuery.URI, DirectoryListQuery.PROJECTION, null, null, null); 19141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 19224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (DEBUG && cursor == null) { 19324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa Log.w(TAG, "null cursor returned for default Email filter query."); 19424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 19541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa results.values = new Cursor[] { directoryCursor, cursor }; 19641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa return results; 19741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 19841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 19941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa @Override 20041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa protected void publishResults(final CharSequence constraint, FilterResults results) { 20141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (results.values != null) { 20241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final Cursor[] cursors = (Cursor[]) results.values; 203a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa onFirstDirectoryLoadFinished(constraint, cursors[0], cursors[1]); 20441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 20541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa results.count = getCount(); 20641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 20741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 20841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa @Override 20941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public CharSequence convertResultToString(Object resultValue) { 210f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira final RecipientEntry entry = (RecipientEntry)resultValue; 21141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final String displayName = entry.getDisplayName(); 21241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final String emailAddress = entry.getDestination(); 21341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, emailAddress)) { 21441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa return emailAddress; 21541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } else { 21641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa return new Rfc822Token(displayName, emailAddress, null).toString(); 21741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 21841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 21941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 22041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 22141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 22241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * An asynchronous filter that performs search in a particular directory. 22341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 22441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa private final class DirectoryFilter extends Filter { 22524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private final DirectorySearchParams mParams; 22641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa private int mLimit; 22741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 22824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa public DirectoryFilter(DirectorySearchParams params) { 22924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa this.mParams = params; 23041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 23141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 23241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public synchronized void setLimit(int limit) { 23341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa this.mLimit = limit; 23441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 23541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 23641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public synchronized int getLimit() { 23741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa return this.mLimit; 23841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 23941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 24041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa @Override 24141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa protected FilterResults performFiltering(CharSequence constraint) { 24224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final FilterResults results = new FilterResults(); 24341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (!TextUtils.isEmpty(constraint)) { 244ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa final Cursor cursor = doQuery(constraint, getLimit(), mParams.directoryId); 24524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (cursor != null) { 24624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa results.values = cursor; 24724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 24841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 24941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 25041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa return results; 25141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 25241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 25341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa @Override 25441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa protected void publishResults(final CharSequence constraint, FilterResults results) { 25541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final Cursor cursor = (Cursor) results.values; 256a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa onDirectoryLoadFinished(constraint, mParams, cursor); 25741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa results.count = getCount(); 25841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 25941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 26041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 26124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private final Context mContext; 26241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa private final ContentResolver mContentResolver; 263ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa private final LayoutInflater mInflater; 264ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa private final int mQueryType; 26541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa private Account mAccount; 26624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private final int mPreferredMaxResultCount; 26741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa private final Handler mHandler = new Handler(); 26841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 26941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 27024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * Each destination (an email address or a phone number) with a valid contactId is first 27124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * inserted into {@link #mEntryMap} and grouped by the contactId. 27224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * Destinations without valid contactId (possible if they aren't in local storage) are stored 27324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * in {@link #mNonAggregatedEntries}. 27424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * Duplicates are removed using {@link #mExistingDestinations}. 27524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * 27624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * After having all results from ContentResolver, all elements in mEntryMap are copied to 27724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * mEntry, which will be used to find items in this Adapter. If the number of contacts in 27824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * mEntries are less than mPreferredMaxResultCount, contacts in 27924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * mNonAggregatedEntries are also used. 28041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 28165b8c0327b00beda9309c7b7c116013d03b06d90Daisuke Miyakawa private final LinkedHashMap<Long, List<RecipientEntry>> mEntryMap; 282f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira private final List<RecipientEntry> mNonAggregatedEntries; 283f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira private final List<RecipientEntry> mEntries; 28424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private final Set<String> mExistingDestinations; 28541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 286a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa /** The number of directories this adapter is waiting for results. */ 287a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa private int mRemainingDirectoryCount; 288a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 28924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa /** 29024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * Used to ignore asynchronous queries with a different constraint, which may appear when 29124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * users type characters quickly. 29224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa */ 29324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private CharSequence mCurrentConstraint; 29424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 29524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private final HandlerThread mPhotoHandlerThread; 29624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private final Handler mPhotoHandler; 29724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private final LruCache<Uri, byte[]> mPhotoCacheMap; 29841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 299ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa /** 300a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa * Handler specific for maintaining "Waiting for more contacts" message, which will be shown 301a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa * when: 302a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa * - there are directories to be searched 303a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa * - results from directories are slow to come 304a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa */ 305a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa private final class DelayedMessageHandler extends Handler { 306a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa @Override 307a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa public void handleMessage(Message msg) { 308a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa if (mRemainingDirectoryCount > 0) { 309a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa constructEntryList(true); 310a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } 311a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } 312a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 313a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa public void sendDelayedLoadMessage() { 314a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa sendMessageDelayed(obtainMessage(MESSAGE_SEARCH_PENDING, 0, 0, null), 315a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa MESSAGE_SEARCH_PENDING_DELAY); 316a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } 317a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 318a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa public void removeDelayedLoadMessage() { 319a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa removeMessages(MESSAGE_SEARCH_PENDING); 320a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } 321a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } 322a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 323a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa private final DelayedMessageHandler mDelayedMessageHandler = new DelayedMessageHandler(); 324a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 325a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa /** 326ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * Constructor for email queries. 327ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa */ 32841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public BaseRecipientAdapter(Context context) { 329ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa this(context, QUERY_TYPE_EMAIL, DEFAULT_PREFERRED_MAX_RESULT_COUNT); 330ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } 331ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa 332ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa public BaseRecipientAdapter(Context context, int queryType) { 333ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa this(context, queryType, DEFAULT_PREFERRED_MAX_RESULT_COUNT); 33441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 33541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 336ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa public BaseRecipientAdapter(Context context, int queryType, int preferredMaxResultCount) { 33741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa mContext = context; 33841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa mContentResolver = context.getContentResolver(); 339ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa mInflater = LayoutInflater.from(context); 340ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa mQueryType = queryType; 34141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa mPreferredMaxResultCount = preferredMaxResultCount; 34265b8c0327b00beda9309c7b7c116013d03b06d90Daisuke Miyakawa mEntryMap = new LinkedHashMap<Long, List<RecipientEntry>>(); 343f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira mNonAggregatedEntries = new ArrayList<RecipientEntry>(); 344f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira mEntries = new ArrayList<RecipientEntry>(); 34524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mExistingDestinations = new HashSet<String>(); 34624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mPhotoHandlerThread = new HandlerThread("photo_handler"); 34724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mPhotoHandlerThread.start(); 34824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mPhotoHandler = new Handler(mPhotoHandlerThread.getLooper()); 34924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mPhotoCacheMap = new LruCache<Uri, byte[]>(PHOTO_CACHE_SIZE); 35041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 35141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 35241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 35341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * Set the account when known. Causes the search to prioritize contacts from that account. 35441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 35541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public void setAccount(Account account) { 35641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa mAccount = account; 35741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 35841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 35941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** Will be called from {@link AutoCompleteTextView} to prepare auto-complete list. */ 36041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa @Override 36141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public Filter getFilter() { 36241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa return new DefaultFilter(); 36341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 36441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 36541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 36641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * Handles the result of the initial call, which brings back the list of directories as well 36741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * as the search results for the local directories. 36824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * 36924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * Must be inside a default Looper thread to avoid synchronization problem. 37041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 37141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa protected void onFirstDirectoryLoadFinished( 37241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa CharSequence constraint, Cursor directoryCursor, Cursor defaultDirectoryCursor) { 37324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mCurrentConstraint = constraint; 37424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 37541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa try { 37624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final List<DirectorySearchParams> paramsList; 37741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (directoryCursor != null) { 37824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa paramsList = setupOtherDirectories(directoryCursor); 37924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } else { 38024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa paramsList = null; 38141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 38241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 38341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa int limit = 0; 38441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 38524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (defaultDirectoryCursor != null) { 38641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa mEntryMap.clear(); 38724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mNonAggregatedEntries.clear(); 38824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mExistingDestinations.clear(); 389a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 390a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa // Reset counters related to directory load. 391a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa mRemainingDirectoryCount = 0; 392a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 39324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa putEntriesWithCursor(defaultDirectoryCursor, true); 394a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa constructEntryList(false); 39541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa limit = mPreferredMaxResultCount - getCount(); 39641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 39741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 39824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (limit > 0 && paramsList != null) { 39924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa searchOtherDirectories(constraint, paramsList, limit); 40041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 40141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } finally { 40241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (directoryCursor != null) { 40341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa directoryCursor.close(); 40441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 40541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (defaultDirectoryCursor != null) { 40641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa defaultDirectoryCursor.close(); 40741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 40841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 40941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 41041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 41124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private List<DirectorySearchParams> setupOtherDirectories(Cursor directoryCursor) { 41241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final PackageManager packageManager = mContext.getPackageManager(); 41324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final List<DirectorySearchParams> paramsList = new ArrayList<DirectorySearchParams>(); 41441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa DirectorySearchParams preferredDirectory = null; 41541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa while (directoryCursor.moveToNext()) { 41641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final long id = directoryCursor.getLong(DirectoryListQuery.ID); 41741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 41841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa // Skip the local invisible directory, because the default directory already includes 41941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa // all local results. 42041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (id == Directory.LOCAL_INVISIBLE) { 42141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa continue; 42241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 42341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 42441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final DirectorySearchParams params = new DirectorySearchParams(); 42541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final String packageName = directoryCursor.getString(DirectoryListQuery.PACKAGE_NAME); 42641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final int resourceId = directoryCursor.getInt(DirectoryListQuery.TYPE_RESOURCE_ID); 42741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa params.directoryId = id; 42841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa params.displayName = directoryCursor.getString(DirectoryListQuery.DISPLAY_NAME); 42941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa params.accountName = directoryCursor.getString(DirectoryListQuery.ACCOUNT_NAME); 43041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa params.accountType = directoryCursor.getString(DirectoryListQuery.ACCOUNT_TYPE); 43141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (packageName != null && resourceId != 0) { 43241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa try { 43341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final Resources resources = 43441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa packageManager.getResourcesForApplication(packageName); 43541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa params.directoryType = resources.getString(resourceId); 43641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (params.directoryType == null) { 43741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Log.e(TAG, "Cannot resolve directory name: " 43841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa + resourceId + "@" + packageName); 43941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 44041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } catch (NameNotFoundException e) { 44141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa Log.e(TAG, "Cannot resolve directory name: " 44241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa + resourceId + "@" + packageName, e); 44341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 44441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 44541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 44641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa // If an account has been provided and we found a directory that 44741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa // corresponds to that account, place that directory second, directly 44841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa // underneath the local contacts. 44941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (mAccount != null && mAccount.name.equals(params.accountName) && 45041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa mAccount.type.equals(params.accountType)) { 45141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa preferredDirectory = params; 45241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } else { 45324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa paramsList.add(params); 45441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 45541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 45641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 45741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (preferredDirectory != null) { 45824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa paramsList.add(1, preferredDirectory); 45941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 46041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 46124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa return paramsList; 46241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 46341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 46441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 46541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * Starts search in other directories 46641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 46724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private void searchOtherDirectories( 46824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa CharSequence constraint, List<DirectorySearchParams> paramsList, int limit) { 46924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final int count = paramsList.size(); 47041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa // Note: skipping the default partition (index 0), which has already been loaded 47141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa for (int i = 1; i < count; i++) { 47224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final DirectorySearchParams params = paramsList.get(i); 47324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa params.constraint = constraint; 47424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (params.filter == null) { 47524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa params.filter = new DirectoryFilter(params); 47624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 47724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa params.filter.setLimit(limit); 47824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa params.filter.filter(constraint); 47924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 480a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 481a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa // Directory search started. We may show "waiting" message if directory results are slow. 482a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa mRemainingDirectoryCount = count - 1; 483a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa mDelayedMessageHandler.sendDelayedLoadMessage(); 48424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 48524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 48624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa /** Must be inside a default Looper thread to avoid synchronization problem. */ 48724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa public void onDirectoryLoadFinished( 48824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa CharSequence constraint, DirectorySearchParams params, Cursor cursor) { 489a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa try { 490a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa mDelayedMessageHandler.removeDelayedLoadMessage(); 491a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 492a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa final boolean usesSameConstraint = TextUtils.equals(constraint, mCurrentConstraint); 493a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa // Check if the received result matches the current constraint. 494a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa // If not - the user must have continued typing after the request was issued, which 495a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa // means several member variables (like mRemainingDirectoryLoad) are already 496a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa // overwritten so shouldn't be touched here anymore. 497a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa if (usesSameConstraint) { 498a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa mRemainingDirectoryCount--; 499a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa if (cursor != null) { 500a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa if (DEBUG) { 501a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa Log.v(TAG, "finished loading directory \"" + params.displayName + "\"" + 50224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa " with query " + constraint); 503a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } 504a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 505a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa if (usesSameConstraint) { 506a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa putEntriesWithCursor(cursor, params.directoryId == Directory.DEFAULT); 507a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } 50824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 50924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 510a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa // Show the list again without "waiting" message. 511a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa constructEntryList(false); 512a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa 513a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa if (mRemainingDirectoryCount > 0) { 514a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa if (DEBUG) { 515a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa Log.v(TAG, "Resend delayed load message. Current mRemainingDirectoryLoad: " 516a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa + mRemainingDirectoryCount); 517a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } 518a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa mDelayedMessageHandler.sendDelayedLoadMessage(); 51924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 520a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } 521a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } finally { 522a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa if (cursor != null) { 52324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa cursor.close(); 52441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 52541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 52641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 52741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 52841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 52941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * Stores each contact information to {@link #mEntryMap}. {@link #mEntries} isn't touched here. 53041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * 53141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * In order to make the new information available from outside Adapter, 532a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa * call {@link #constructEntryList(boolean)} after this method. 53341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 53424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa private void putEntriesWithCursor(Cursor cursor, boolean validContactId) { 53541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa cursor.move(-1); 53641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa while (cursor.moveToNext()) { 537ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa final String displayName; 538ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa final String destination; 53965b8c0327b00beda9309c7b7c116013d03b06d90Daisuke Miyakawa final long contactId; 54065b8c0327b00beda9309c7b7c116013d03b06d90Daisuke Miyakawa final long dataId; 541ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa final String thumbnailUriString; 542ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa if (mQueryType == QUERY_TYPE_EMAIL) { 543ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa displayName = cursor.getString(EmailQuery.NAME); 544ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa destination = cursor.getString(EmailQuery.ADDRESS); 54565b8c0327b00beda9309c7b7c116013d03b06d90Daisuke Miyakawa contactId = cursor.getLong(EmailQuery.CONTACT_ID); 54665b8c0327b00beda9309c7b7c116013d03b06d90Daisuke Miyakawa dataId = cursor.getLong(EmailQuery.DATA_ID); 547ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa thumbnailUriString = cursor.getString(EmailQuery.PHOTO_THUMBNAIL_URI); 548ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } else if (mQueryType == QUERY_TYPE_PHONE) { 549ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa displayName = cursor.getString(PhoneQuery.NAME); 550ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa destination = cursor.getString(PhoneQuery.NUMBER); 55165b8c0327b00beda9309c7b7c116013d03b06d90Daisuke Miyakawa contactId = cursor.getLong(PhoneQuery.CONTACT_ID); 55265b8c0327b00beda9309c7b7c116013d03b06d90Daisuke Miyakawa dataId = cursor.getLong(PhoneQuery.DATA_ID); 553ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa thumbnailUriString = cursor.getString(PhoneQuery.PHOTO_THUMBNAIL_URI); 554ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } else { 555ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa throw new IndexOutOfBoundsException("Unexpected query type: " + mQueryType); 556ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } 55724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 55824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa // Note: At this point each entry doesn't contain have any photo (thus getPhotoBytes() 55924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa // returns null). 56024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 56124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (mExistingDestinations.contains(destination)) { 56224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa continue; 56324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 56424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mExistingDestinations.add(destination); 56541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 56624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (!validContactId) { 567f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira mNonAggregatedEntries.add(RecipientEntry.constructTopLevelEntry( 568b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa displayName, destination, contactId, dataId, thumbnailUriString)); 56924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } else if (mEntryMap.containsKey(contactId)) { 57041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa // We already have a section for the person. 571f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira final List<RecipientEntry> entryList = mEntryMap.get(contactId); 572f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira entryList.add(RecipientEntry.constructSecondLevelEntry( 57390081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira displayName, destination, contactId, dataId, thumbnailUriString)); 57441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } else { 575f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira final List<RecipientEntry> entryList = new ArrayList<RecipientEntry>(); 576f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira entryList.add(RecipientEntry.constructTopLevelEntry( 577b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa displayName, destination, contactId, dataId, thumbnailUriString)); 57841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa mEntryMap.put(contactId, entryList); 57941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 58041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 58141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 58241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 58341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 58424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * Constructs an actual list for this Adapter using {@link #mEntryMap}. Also tries to 58524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * fetch a cached photo for each contact entry (other than separators), or request another 58624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * thread to get one from directories. The thread ({@link #mPhotoHandlerThread}) will 58724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa * request {@link #notifyDataSetChanged()} after having the photo asynchronously. 58841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 589a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa private void constructEntryList(boolean showMessageIfDirectoryLoadRemaining) { 59024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mEntries.clear(); 59124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa int validEntryCount = 0; 59265b8c0327b00beda9309c7b7c116013d03b06d90Daisuke Miyakawa for (Map.Entry<Long, List<RecipientEntry>> mapEntry : mEntryMap.entrySet()) { 593f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira final List<RecipientEntry> entryList = mapEntry.getValue(); 59441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa final int size = entryList.size(); 59541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa for (int i = 0; i < size; i++) { 596f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira RecipientEntry entry = entryList.get(i); 59741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa mEntries.add(entry); 59824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa tryFetchPhoto(entry); 59924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa validEntryCount++; 60041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (i < size - 1) { 601f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira mEntries.add(RecipientEntry.SEP_WITHIN_GROUP); 60241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 60341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 604f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira mEntries.add(RecipientEntry.SEP_NORMAL); 60524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (validEntryCount > mPreferredMaxResultCount) { 60624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa break; 60724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 60841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 60924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (validEntryCount <= mPreferredMaxResultCount) { 610f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira for (RecipientEntry entry : mNonAggregatedEntries) { 61124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (validEntryCount > mPreferredMaxResultCount) { 61224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa break; 61324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 61424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mEntries.add(entry); 61524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa tryFetchPhoto(entry); 61624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 617f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira mEntries.add(RecipientEntry.SEP_NORMAL); 61824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa validEntryCount++; 61924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 62024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 62124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 622a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa if (showMessageIfDirectoryLoadRemaining && mRemainingDirectoryCount > 0) { 623a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa mEntries.add(RecipientEntry.WAITING_FOR_DIRECTORY_SEARCH); 624a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } else { 625a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa // Remove last divider 626a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa if (mEntries.size() > 1) { 627a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa mEntries.remove(mEntries.size() - 1); 628a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } 62941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 63041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa notifyDataSetChanged(); 63141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 63241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 633f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira private void tryFetchPhoto(final RecipientEntry entry) { 63424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final Uri photoThumbnailUri = entry.getPhotoThumbnailUri(); 63524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (photoThumbnailUri != null) { 63624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final byte[] photoBytes = mPhotoCacheMap.get(photoThumbnailUri); 63724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (photoBytes != null) { 63824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa entry.setPhotoBytes(photoBytes); 63924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa // notifyDataSetChanged() should be called by a caller. 64024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } else { 64124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (DEBUG) { 64224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa Log.d(TAG, "No photo cache for " + entry.getDisplayName() 64324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa + ". Fetch one asynchronously"); 64441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 64524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa fetchPhotoAsync(entry, photoThumbnailUri); 64641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 64741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 64841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 64941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 650f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira private void fetchPhotoAsync(final RecipientEntry entry, final Uri photoThumbnailUri) { 65124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mPhotoHandler.post(new Runnable() { 65224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa @Override 65324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa public void run() { 65424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final Cursor photoCursor = mContentResolver.query( 65524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa photoThumbnailUri, PhotoQuery.PROJECTION, null, null, null); 65624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (photoCursor != null) { 65724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa try { 65824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (photoCursor.moveToFirst()) { 65924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final byte[] photoBytes = photoCursor.getBlob(PhotoQuery.PHOTO); 66024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa entry.setPhotoBytes(photoBytes); 66124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 66224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mHandler.post(new Runnable() { 66324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa @Override 66424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa public void run() { 66524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mPhotoCacheMap.put(photoThumbnailUri, photoBytes); 66624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa notifyDataSetChanged(); 66724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 66824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa }); 66924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 67024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } finally { 67124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa photoCursor.close(); 67224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 67324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 67424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 67524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa }); 67624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 67724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 67890081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira protected void fetchPhoto(final RecipientEntry entry, final Uri photoThumbnailUri) { 67990081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira byte[] photoBytes = mPhotoCacheMap.get(photoThumbnailUri); 68090081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira if (photoBytes != null) { 68190081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira entry.setPhotoBytes(photoBytes); 68290081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira return; 68390081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira } 68490081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira final Cursor photoCursor = mContentResolver.query(photoThumbnailUri, PhotoQuery.PROJECTION, 68590081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira null, null, null); 68690081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira if (photoCursor != null) { 68790081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira try { 68890081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira if (photoCursor.moveToFirst()) { 68990081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira photoBytes = photoCursor.getBlob(PhotoQuery.PHOTO); 69090081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira entry.setPhotoBytes(photoBytes); 69190081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira mPhotoCacheMap.put(photoThumbnailUri, photoBytes); 69290081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira } 69390081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira } finally { 69490081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira photoCursor.close(); 69590081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira } 69690081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira } 69790081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira } 69890081ee88c7eb216ea22f426aa6856e310a867e1Mindy Pereira 699ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa private Cursor doQuery(CharSequence constraint, int limit, Long directoryId) { 700ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa final Cursor cursor; 701ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa if (mQueryType == QUERY_TYPE_EMAIL) { 702ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa final Uri.Builder builder = Email.CONTENT_FILTER_URI.buildUpon() 703ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa .appendPath(constraint.toString()) 704ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, 705ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa String.valueOf(limit + ALLOWANCE_FOR_DUPLICATES)); 706ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa if (directoryId != null) { 707ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 708ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa String.valueOf(directoryId)); 709ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } 710b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa if (mAccount != null) { 711b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa builder.appendQueryParameter(PRIMARY_ACCOUNT_NAME, mAccount.name); 712b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa builder.appendQueryParameter(PRIMARY_ACCOUNT_TYPE, mAccount.type); 713b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa } 714ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa cursor = mContentResolver.query( 715ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa builder.build(), EmailQuery.PROJECTION, null, null, null); 716ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } else if (mQueryType == QUERY_TYPE_PHONE){ 717ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa final Uri.Builder builder = Phone.CONTENT_FILTER_URI.buildUpon() 718ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa .appendPath(constraint.toString()) 719ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, 720ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa String.valueOf(limit + ALLOWANCE_FOR_DUPLICATES)); 721ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa if (directoryId != null) { 722ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 723ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa String.valueOf(directoryId)); 724ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } 725b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa if (mAccount != null) { 726b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa builder.appendQueryParameter(PRIMARY_ACCOUNT_NAME, mAccount.name); 727b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa builder.appendQueryParameter(PRIMARY_ACCOUNT_TYPE, mAccount.type); 728b5ebb8916a1bb178062a0ccb59e80de27ec1bb2dDaisuke Miyakawa } 729ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa cursor = mContentResolver.query( 730ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa builder.build(), PhoneQuery.PROJECTION, null, null, null); 731ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } else { 732ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa cursor = null; 733ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } 734ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa return cursor; 735ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } 736ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa 73741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public void close() { 73824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mEntryMap.clear(); 73924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mNonAggregatedEntries.clear(); 74024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mExistingDestinations.clear(); 74124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mEntries.clear(); 74224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa mPhotoCacheMap.evictAll(); 74324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (!mPhotoHandlerThread.quit()) { 74424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa Log.w(TAG, "Failed to quit photo handler thread, ignoring it."); 74524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 74641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 74741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 74841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa @Override 74941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public int getCount() { 75024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa return mEntries.size(); 75141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 75241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 75341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa @Override 75441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public Object getItem(int position) { 75524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa return mEntries.get(position); 75641caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 75741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 75841caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa @Override 75941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa public long getItemId(int position) { 76041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa return position; 76141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 76241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 76341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa @Override 76424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa public int getViewTypeCount() { 765f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira return RecipientEntry.ENTRY_TYPE_SIZE; 76624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 76724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa 76824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa @Override 76924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa public int getItemViewType(int position) { 77024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa return mEntries.get(position).getEntryType(); 77124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 77241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 77324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa @Override 77424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa public View getView(int position, View convertView, ViewGroup parent) { 775f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira final RecipientEntry entry = mEntries.get(position); 77624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa switch (entry.getEntryType()) { 777f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira case RecipientEntry.ENTRY_TYPE_SEP_NORMAL: { 778ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa return convertView != null ? convertView 779ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa : mInflater.inflate(getSeparatorLayout(), parent, false); 78041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 781f566dee91901e44db63df3bf393afb1d43a36f78Mindy Pereira case RecipientEntry.ENTRY_TYPE_SEP_WITHIN_GROUP: { 78224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa return convertView != null ? convertView 783ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa : mInflater.inflate(getSeparatorWithinGroupLayout(), parent, false); 78441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 785a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa case RecipientEntry.ENTRY_TYPE_WAITING_FOR_DIRECTORY_SEARCH: { 786a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa return convertView != null ? convertView 787a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa : mInflater.inflate(getWaitingForDirectorySearchLayout(), parent, false); 788a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa } 78924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa default: { 79024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa String displayName = entry.getDisplayName(); 79124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa String emailAddress = entry.getDestination(); 79224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (TextUtils.isEmpty(displayName) 79324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa || TextUtils.equals(displayName, emailAddress)) { 79424a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa displayName = emailAddress; 79524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa emailAddress = null; 79624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 79741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 798ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa final View itemView = convertView != null ? convertView 799ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa : mInflater.inflate(getItemLayout(), parent, false); 800ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa final TextView displayNameView = 801ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa (TextView)itemView.findViewById(getDisplayNameId()); 802ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa final TextView emailAddressView = 803ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa (TextView)itemView.findViewById(getDestinationId()); 804ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa final ImageView imageView = (ImageView)itemView.findViewById(getPhotoId()); 80524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa displayNameView.setText(displayName); 80624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (!TextUtils.isEmpty(emailAddress)) { 80724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa emailAddressView.setText(emailAddress); 8084690ffedeed9a067ecef01e26107b58173b3712aDaisuke Miyakawa } else { 8094690ffedeed9a067ecef01e26107b58173b3712aDaisuke Miyakawa emailAddressView.setText(null); 81024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 81141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa if (entry.isFirstLevel()) { 81224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa displayNameView.setVisibility(View.VISIBLE); 81324a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (imageView != null) { 814ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa imageView.setVisibility(View.VISIBLE); 81524a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final byte[] photoBytes = entry.getPhotoBytes(); 81624a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa if (photoBytes != null && imageView != null) { 81724a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa final Bitmap photo = BitmapFactory.decodeByteArray( 81824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa photoBytes, 0, photoBytes.length); 81924a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa imageView.setImageBitmap(photo); 82024a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } else { 82124a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa imageView.setImageResource(getDefaultPhotoResource()); 82224a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa } 82341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 82441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } else { 82541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa displayNameView.setVisibility(View.GONE); 826ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa if (imageView != null) imageView.setVisibility(View.GONE); 82741caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 82824a05a268d1fa2839d62361dc50b88a4c2a2975bDaisuke Miyakawa return itemView; 82941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 83041caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 83141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa } 83241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 83341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 834ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * Returns a layout id for each item inside auto-complete list. 835ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * 836ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * Each View must contain two TextViews (for display name and destination) and one ImageView 837ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * (for photo). Ids for those should be available via {@link #getDisplayNameId()}, 838ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * {@link #getDestinationId()}, and {@link #getPhotoId()}. 83941caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 840078509f1fd42ec04b46565ecc26f4f527b277c5cMindy Pereira protected abstract int getItemLayout(); 841ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa /** Returns a layout id for a separator dividing two person or groups. */ 842078509f1fd42ec04b46565ecc26f4f527b277c5cMindy Pereira protected abstract int getSeparatorLayout(); 84341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 844ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * Returns a layout id for a separator dividing two destinations for a same person or group. 84541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 846078509f1fd42ec04b46565ecc26f4f527b277c5cMindy Pereira protected abstract int getSeparatorWithinGroupLayout(); 847a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa /** 848a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa * Returns a layout id for a view showing "waiting for more contacts". 849a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa */ 850a601adc796fa7276771e6ab2670bf50663555489Daisuke Miyakawa protected abstract int getWaitingForDirectorySearchLayout(); 85141caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa 85241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa /** 85341caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * Returns a resource ID representing an image which should be shown when ther's no relevant 85441caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa * photo is available. 85541caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa */ 856078509f1fd42ec04b46565ecc26f4f527b277c5cMindy Pereira protected abstract int getDefaultPhotoResource(); 857ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa 858ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa /** 859ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * Returns an id for TextView in an item View for showing a display name. In default 860ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * {@link android.R.id#text1} is returned. 861ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa */ 862ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa protected int getDisplayNameId() { 863ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa return android.R.id.text1; 864ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } 865ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa 866ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa /** 867ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * Returns an id for TextView in an item View for showing a destination 868ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * (an email address or a phone number). 869ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * In default {@link android.R.id#text2} is returned. 870ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa */ 871ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa protected int getDestinationId() { 872ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa return android.R.id.text2; 873ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } 874ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa 875ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa /** 876ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * Returns an id for ImageView in an item View for showing photo image for a person. In default 877ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa * {@link android.R.id#icon} is returned. 878ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa */ 879ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa protected int getPhotoId() { 880ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa return android.R.id.icon; 881ef2f73347ae0bf87b2874b6360ff06c5f430c68fDaisuke Miyakawa } 88241caab4c41a94712f8eeb1585422df52f8ab5db2Daisuke Miyakawa} 883