BaseRecipientAdapter.java revision 31c33ef87cb0612250b812233ffbc0c46e88a371
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.net.Uri; 276ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.os.Handler; 284bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawaimport android.os.Message; 296ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.provider.ContactsContract; 306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.provider.ContactsContract.Directory; 316ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.text.TextUtils; 326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.text.util.Rfc822Token; 336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.util.Log; 346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.view.View; 356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.view.ViewGroup; 366ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.AutoCompleteTextView; 376ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.BaseAdapter; 386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.Filter; 396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.Filterable; 40b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 41b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport com.android.ex.chips.DropdownChipLayouter.AdapterType; 426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 436ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport java.util.ArrayList; 44fa7b0fb73f80ceafdf3ff3260b345b61d2766f93Scott Kennedyimport java.util.Collections; 4574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawaimport java.util.HashSet; 46cf9337aa4b2d844f4941d75832f52266c4fc3fa7Daisuke Miyakawaimport java.util.LinkedHashMap; 476ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport java.util.List; 486ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport java.util.Map; 4974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawaimport java.util.Set; 506ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 516ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa/** 526ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Adapter for showing a recipient list. 536ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 548af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sappersteinpublic class BaseRecipientAdapter extends BaseAdapter implements Filterable, AccountSpecifier, 558af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein PhotoManager.PhotoManagerCallback { 566ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private static final String TAG = "BaseRecipientAdapter"; 578383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 586b616f1d06b092825da345078ce4a899b829290dDaisuke Miyakawa private static final boolean DEBUG = false; 596ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 606ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 616ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * The preferred number of results to be retrieved. This number may be 626ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * exceeded if there are several directories configured, because we will use 636ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * the same limit for all directories. 646ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 656ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private static final int DEFAULT_PREFERRED_MAX_RESULT_COUNT = 10; 666ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 676ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 686ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * The number of extra entries requested to allow for duplicates. Duplicates 696ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * are removed from the overall result. 706ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 7116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp static final int ALLOWANCE_FOR_DUPLICATES = 5; 726ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 737537f840506bcb642bed9dc1c2bdcf6d31c6b2a7Daisuke Miyakawa // This is ContactsContract.PRIMARY_ACCOUNT_NAME. Available from ICS as hidden 7416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp static final String PRIMARY_ACCOUNT_NAME = "name_for_primary_account"; 757537f840506bcb642bed9dc1c2bdcf6d31c6b2a7Daisuke Miyakawa // This is ContactsContract.PRIMARY_ACCOUNT_TYPE. Available from ICS as hidden 7616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp static final String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account"; 777537f840506bcb642bed9dc1c2bdcf6d31c6b2a7Daisuke Miyakawa 784bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa /** 794bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * The "Waiting for more contacts" message will be displayed if search is not complete 804bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * within this many milliseconds. 814bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa */ 824bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa private static final int MESSAGE_SEARCH_PENDING_DELAY = 1000; 834bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa /** Used to prepare "Waiting for more contacts" message. */ 844bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa private static final int MESSAGE_SEARCH_PENDING = 1; 854bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 86d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public static final int QUERY_TYPE_EMAIL = 0; 87d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public static final int QUERY_TYPE_PHONE = 1; 88d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa 891db635b5a09c77a27fe17a9ce31c21a67458c2bcAndrew Sapperstein private final Queries.Query mQueryMode; 9080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor private final int mQueryType; 9180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 926ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 936ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Model object for a {@link Directory} row. 946ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 956ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public final static class DirectorySearchParams { 966ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public long directoryId; 976ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String directoryType; 986ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String displayName; 996ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String accountName; 1006ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String accountType; 1016ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public CharSequence constraint; 1026ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public DirectoryFilter filter; 1036ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1046ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 10516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp protected static class DirectoryListQuery { 1066ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1076ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final Uri URI = 1086ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "directories"); 1096ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final String[] PROJECTION = { 1106ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory._ID, // 0 1116ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.ACCOUNT_NAME, // 1 1126ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.ACCOUNT_TYPE, // 2 1136ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.DISPLAY_NAME, // 3 1146ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.PACKAGE_NAME, // 4 1156ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.TYPE_RESOURCE_ID, // 5 1166ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa }; 1176ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1186ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int ID = 0; 1196ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int ACCOUNT_NAME = 1; 1206ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int ACCOUNT_TYPE = 2; 1216ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int DISPLAY_NAME = 3; 1226ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int PACKAGE_NAME = 4; 1236ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int TYPE_RESOURCE_ID = 5; 1246ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1256ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1268383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa /** Used to temporarily hold results in Cursor objects. */ 12776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert protected static class TemporaryEntry { 1288383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final String displayName; 1298383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final String destination; 1307211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa public final int destinationType; 1317211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa public final String destinationLabel; 1328383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final long contactId; 1337a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy public final Long directoryId; 1348383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final long dataId; 1358383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final String thumbnailUriString; 13600adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki public final int displayNameSource; 1377a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy public final String lookupKey; 1388383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 13976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert public TemporaryEntry( 14076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert String displayName, 14176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert String destination, 14276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert int destinationType, 14376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert String destinationLabel, 14476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert long contactId, 1457a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy Long directoryId, 14676f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert long dataId, 14776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert String thumbnailUriString, 148514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy int displayNameSource, 1497a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy String lookupKey) { 15076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.displayName = displayName; 15176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.destination = destination; 15276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.destinationType = destinationType; 15376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.destinationLabel = destinationLabel; 15476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.contactId = contactId; 1557a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy this.directoryId = directoryId; 15676f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.dataId = dataId; 15776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.thumbnailUriString = thumbnailUriString; 15876f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.displayNameSource = displayNameSource; 1597a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy this.lookupKey = lookupKey; 16076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 16176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert 1627a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy public TemporaryEntry(Cursor cursor, Long directoryId) { 16380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.displayName = cursor.getString(Queries.Query.NAME); 16480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.destination = cursor.getString(Queries.Query.DESTINATION); 16580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.destinationType = cursor.getInt(Queries.Query.DESTINATION_TYPE); 16680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.destinationLabel = cursor.getString(Queries.Query.DESTINATION_LABEL); 16780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.contactId = cursor.getLong(Queries.Query.CONTACT_ID); 1687a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy this.directoryId = directoryId; 16980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.dataId = cursor.getLong(Queries.Query.DATA_ID); 17080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.thumbnailUriString = cursor.getString(Queries.Query.PHOTO_THUMBNAIL_URI); 17100adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki this.displayNameSource = cursor.getInt(Queries.Query.DISPLAY_NAME_SOURCE); 1727a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy this.lookupKey = cursor.getString(Queries.Query.LOOKUP_KEY); 1738383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 1748383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 1758383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 1768383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa /** 1778383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * Used to pass results from {@link DefaultFilter#performFiltering(CharSequence)} to 1788383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link DefaultFilter#publishResults(CharSequence, android.widget.Filter.FilterResults)} 1798383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa */ 1808383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private static class DefaultFilterResult { 1818383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final List<RecipientEntry> entries; 1828383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final LinkedHashMap<Long, List<RecipientEntry>> entryMap; 1838383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final List<RecipientEntry> nonAggregatedEntries; 1848383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final Set<String> existingDestinations; 1858383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final List<DirectorySearchParams> paramsList; 1868383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 1878383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public DefaultFilterResult(List<RecipientEntry> entries, 1888383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa LinkedHashMap<Long, List<RecipientEntry>> entryMap, 1898383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa List<RecipientEntry> nonAggregatedEntries, 1908383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Set<String> existingDestinations, 1918383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa List<DirectorySearchParams> paramsList) { 1928383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa this.entries = entries; 1938383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa this.entryMap = entryMap; 1948383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa this.nonAggregatedEntries = nonAggregatedEntries; 1958383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa this.existingDestinations = existingDestinations; 1968383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa this.paramsList = paramsList; 1978383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 1988383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 1998383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2006ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 2016ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * An asynchronous filter used for loading two data sets: email rows from the local 2026ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * contact provider and the list of {@link Directory}'s. 2036ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 2046ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private final class DefaultFilter extends Filter { 2056ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2066ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 2076ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected FilterResults performFiltering(CharSequence constraint) { 2088383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 2098383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.d(TAG, "start filtering. constraint: " + constraint + ", thread:" 2108383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + Thread.currentThread()); 2118383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2128383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 21374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final FilterResults results = new FilterResults(); 2148383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Cursor defaultDirectoryCursor = null; 2158383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Cursor directoryCursor = null; 2168383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2178383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (TextUtils.isEmpty(constraint)) { 21837726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook clearTempEntries(); 2198383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Return empty results. 2208383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa return results; 2216ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2226ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2238383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa try { 2247a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy defaultDirectoryCursor = doQuery(constraint, mPreferredMaxResultCount, 2257a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy null /* directoryId */); 22680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 2278383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (defaultDirectoryCursor == null) { 2288383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 2298383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.w(TAG, "null cursor returned for default Email filter query."); 2308383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2318383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } else { 2328383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // These variables will become mEntries, mEntryMap, mNonAggregatedEntries, and 2338383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // mExistingDestinations. Here we shouldn't use those member variables directly 2348383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // since this method is run outside the UI thread. 2358383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final LinkedHashMap<Long, List<RecipientEntry>> entryMap = 2368383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa new LinkedHashMap<Long, List<RecipientEntry>>(); 2378383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final List<RecipientEntry> nonAggregatedEntries = 2388383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa new ArrayList<RecipientEntry>(); 2398383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final Set<String> existingDestinations = new HashSet<String>(); 2408383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2418383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa while (defaultDirectoryCursor.moveToNext()) { 2428383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Note: At this point each entry doesn't contain any photo 2438383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // (thus getPhotoBytes() returns null). 244514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy putOneEntry(new TemporaryEntry(defaultDirectoryCursor, 2457a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy null /* directoryId */), 2468383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa true, entryMap, nonAggregatedEntries, existingDestinations); 2478383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2488383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2498383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // We'll copy this result to mEntry in publicResults() (run in the UX thread). 250f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy final List<RecipientEntry> entries = constructEntryList( 251f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy entryMap, nonAggregatedEntries); 2528383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2538af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein final List<DirectorySearchParams> paramsList = 2548af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein searchOtherDirectories(existingDestinations); 2556ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2568383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.values = new DefaultFilterResult( 2578383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entries, entryMap, nonAggregatedEntries, 2588383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa existingDestinations, paramsList); 2598383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.count = 1; 2608383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2618383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } finally { 2628383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (defaultDirectoryCursor != null) { 2638383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa defaultDirectoryCursor.close(); 2648383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2658383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (directoryCursor != null) { 2668383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa directoryCursor.close(); 2678383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 26874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 2696ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return results; 2706ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2716ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2726ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 2736ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected void publishResults(final CharSequence constraint, FilterResults results) { 2748383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mCurrentConstraint = constraint; 2758383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 27637726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook clearTempEntries(); 27737726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 2786ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (results.values != null) { 2798383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa DefaultFilterResult defaultFilterResult = (DefaultFilterResult) results.values; 2808383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mEntryMap = defaultFilterResult.entryMap; 2818383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mNonAggregatedEntries = defaultFilterResult.nonAggregatedEntries; 2828383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mExistingDestinations = defaultFilterResult.existingDestinations; 2838383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 28431c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao cacheCurrentEntriesIfNeeded(defaultFilterResult.entries.size(), 28531c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao defaultFilterResult.paramsList == null ? 0 : 28631c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao defaultFilterResult.paramsList.size()); 28737726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 2888383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa updateEntries(defaultFilterResult.entries); 2898383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2908383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // We need to search other remote directories, doing other Filter requests. 2918383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (defaultFilterResult.paramsList != null) { 2928383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final int limit = mPreferredMaxResultCount - 2938383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa defaultFilterResult.existingDestinations.size(); 2948383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa startSearchOtherDirectories(constraint, defaultFilterResult.paramsList, limit); 2958383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 296fa7b0fb73f80ceafdf3ff3260b345b61d2766f93Scott Kennedy } else { 297fa7b0fb73f80ceafdf3ff3260b345b61d2766f93Scott Kennedy updateEntries(Collections.<RecipientEntry>emptyList()); 2986ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2996ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3006ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3016ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 3026ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public CharSequence convertResultToString(Object resultValue) { 303f621a601e1f966c89b7aadbcca384021e14d668dMindy Pereira final RecipientEntry entry = (RecipientEntry)resultValue; 3046ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final String displayName = entry.getDisplayName(); 3056ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final String emailAddress = entry.getDestination(); 3066ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, emailAddress)) { 3076ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return emailAddress; 3086ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } else { 3096ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return new Rfc822Token(displayName, emailAddress, null).toString(); 3106ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3116ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3126ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3136ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3148af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein protected List<DirectorySearchParams> searchOtherDirectories(Set<String> existingDestinations) { 3158af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein // After having local results, check the size of results. If the results are 3168af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein // not enough, we search remote directories, which will take longer time. 3178af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein final int limit = mPreferredMaxResultCount - existingDestinations.size(); 3188af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein if (limit > 0) { 3198af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein if (DEBUG) { 3208af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein Log.d(TAG, "More entries should be needed (current: " 3218af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein + existingDestinations.size() 3228af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein + ", remaining limit: " + limit + ") "); 3238af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 3248af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein final Cursor directoryCursor = mContentResolver.query( 3258af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein DirectoryListQuery.URI, DirectoryListQuery.PROJECTION, 3268af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein null, null, null); 3278af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein return setupOtherDirectories(mContext, directoryCursor, mAccount); 3288af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } else { 3298af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein // We don't need to search other directories. 3308af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein return null; 3318af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 3328af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 3338af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 3346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 3356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * An asynchronous filter that performs search in a particular directory. 3366ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 33776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert protected class DirectoryFilter extends Filter { 33874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final DirectorySearchParams mParams; 3396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private int mLimit; 3406ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 34174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public DirectoryFilter(DirectorySearchParams params) { 3428383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mParams = params; 3436ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3446ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3456ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public synchronized void setLimit(int limit) { 3466ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa this.mLimit = limit; 3476ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3486ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3496ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public synchronized int getLimit() { 3506ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return this.mLimit; 3516ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3526ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3536ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 3546ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected FilterResults performFiltering(CharSequence constraint) { 3558383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 3568383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.d(TAG, "DirectoryFilter#performFiltering. directoryId: " + mParams.directoryId 3578383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + ", constraint: " + constraint + ", thread: " + Thread.currentThread()); 3588383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 35974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final FilterResults results = new FilterResults(); 3608383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.values = null; 3618383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.count = 0; 3628383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 3636ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (!TextUtils.isEmpty(constraint)) { 3648383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final ArrayList<TemporaryEntry> tempEntries = new ArrayList<TemporaryEntry>(); 3658383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 3668383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Cursor cursor = null; 3678383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa try { 3688383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // We don't want to pass this Cursor object to UI thread (b/5017608). 3698383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Assuming the result should contain fairly small results (at most ~10), 3708383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // We just copy everything to local structure. 3718383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa cursor = doQuery(constraint, getLimit(), mParams.directoryId); 37280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 3738383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (cursor != null) { 3748383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa while (cursor.moveToNext()) { 3757a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy tempEntries.add(new TemporaryEntry(cursor, mParams.directoryId)); 3768383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 3778383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 3788383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } finally { 3798383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (cursor != null) { 3808383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa cursor.close(); 3818383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 38274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 3838383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (!tempEntries.isEmpty()) { 3848383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.values = tempEntries; 3858383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.count = 1; 3868383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 3878383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 3888383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 3898383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 3908383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.v(TAG, "finished loading directory \"" + mParams.displayName + "\"" + 3918383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa " with query " + constraint); 3926ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3936ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3946ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return results; 3956ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3966ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3976ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 3986ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected void publishResults(final CharSequence constraint, FilterResults results) { 3998383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 4008383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.d(TAG, "DirectoryFilter#publishResult. constraint: " + constraint 4018383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + ", mCurrentConstraint: " + mCurrentConstraint); 4028383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4038383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mDelayedMessageHandler.removeDelayedLoadMessage(); 4048383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Check if the received result matches the current constraint 4058383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // If not - the user must have continued typing after the request was issued, which 4068383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // means several member variables (like mRemainingDirectoryLoad) are already 4078383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // overwritten so shouldn't be touched here anymore. 4088383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (TextUtils.equals(constraint, mCurrentConstraint)) { 4098383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (results.count > 0) { 410dfd7e0774f9a4f47c127b21e5468430374340f66Andy Huang @SuppressWarnings("unchecked") 4118383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final ArrayList<TemporaryEntry> tempEntries = 4128383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa (ArrayList<TemporaryEntry>) results.values; 4138383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 4148383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa for (TemporaryEntry tempEntry : tempEntries) { 4158af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein putOneEntry(tempEntry, mParams.directoryId == Directory.DEFAULT); 4168383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4178383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4188383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 4198383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // If there are remaining directories, set up delayed message again. 4208383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mRemainingDirectoryCount--; 4218383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (mRemainingDirectoryCount > 0) { 4228383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 4238383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.d(TAG, "Resend delayed load message. Current mRemainingDirectoryLoad: " 4248383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + mRemainingDirectoryCount); 4258383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4268383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mDelayedMessageHandler.sendDelayedLoadMessage(); 4278383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 42837726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 42937726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook // If this directory result has some items, or there are no more directories that 43037726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook // we are waiting for, clear the temp results 43137726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook if (results.count > 0 || mRemainingDirectoryCount == 0) { 43237726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook // Clear the temp entries 43337726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook clearTempEntries(); 43437726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook } 4358383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4368383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 4378383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Show the list again without "waiting" message. 4388af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein updateEntries(constructEntryList()); 4396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4406ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4416ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 44274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final Context mContext; 4436ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private final ContentResolver mContentResolver; 4446ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private Account mAccount; 4458af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein protected final int mPreferredMaxResultCount; 446b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin private DropdownChipLayouter mDropdownChipLayouter; 4476ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 4486ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 4498383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link #mEntries} is responsible for showing every result for this Adapter. To 4508383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * construct it, we use {@link #mEntryMap}, {@link #mNonAggregatedEntries}, and 4518383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link #mExistingDestinations}. 4528383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * 4538383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * First, each destination (an email address or a phone number) with a valid contactId is 4548383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * inserted into {@link #mEntryMap} and grouped by the contactId. Destinations without valid 4558383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * contactId (possible if they aren't in local storage) are stored in 4568383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link #mNonAggregatedEntries}. 45774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * Duplicates are removed using {@link #mExistingDestinations}. 45874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * 4598383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * After having all results from Cursor objects, all destinations in mEntryMap are copied to 4608383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link #mEntries}. If the number of destinations is not enough (i.e. less than 4618383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link #mPreferredMaxResultCount}), destinations in mNonAggregatedEntries are also used. 4628383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * 4638383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * These variables are only used in UI thread, thus should not be touched in 4648383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * performFiltering() methods. 4656ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 4668383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private LinkedHashMap<Long, List<RecipientEntry>> mEntryMap; 4678383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private List<RecipientEntry> mNonAggregatedEntries; 4688383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private Set<String> mExistingDestinations; 4698383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa /** Note: use {@link #updateEntries(List)} to update this variable. */ 4708383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private List<RecipientEntry> mEntries; 47137726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook private List<RecipientEntry> mTempEntries; 4726ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 4734bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa /** The number of directories this adapter is waiting for results. */ 4744bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa private int mRemainingDirectoryCount; 4754bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 47674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa /** 4778383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * Used to ignore asynchronous queries with a different constraint, which may happen when 47874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * users type characters quickly. 47974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa */ 4808af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein protected CharSequence mCurrentConstraint; 48174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 4828af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein /** 4838af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * Performs all photo querying as well as caching for repeated lookups. 4848af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein */ 4858af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein private PhotoManager mPhotoManager; 4866ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 487d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa /** 4884bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * Handler specific for maintaining "Waiting for more contacts" message, which will be shown 4894bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * when: 4904bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * - there are directories to be searched 4914bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * - results from directories are slow to come 4924bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa */ 4934bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa private final class DelayedMessageHandler extends Handler { 4944bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa @Override 4954bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa public void handleMessage(Message msg) { 4964bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa if (mRemainingDirectoryCount > 0) { 4978af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein updateEntries(constructEntryList()); 4984bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa } 4994bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa } 5004bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 5014bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa public void sendDelayedLoadMessage() { 5024bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa sendMessageDelayed(obtainMessage(MESSAGE_SEARCH_PENDING, 0, 0, null), 5034bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa MESSAGE_SEARCH_PENDING_DELAY); 5044bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa } 5054bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 5064bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa public void removeDelayedLoadMessage() { 5074bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa removeMessages(MESSAGE_SEARCH_PENDING); 5084bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa } 5094bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa } 5104bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 5114bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa private final DelayedMessageHandler mDelayedMessageHandler = new DelayedMessageHandler(); 5124bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 5138c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp private EntriesUpdatedObserver mEntriesUpdatedObserver; 5148c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp 5154bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa /** 516d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * Constructor for email queries. 517d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa */ 5186ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public BaseRecipientAdapter(Context context) { 51980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this(context, DEFAULT_PREFERRED_MAX_RESULT_COUNT, QUERY_TYPE_EMAIL); 5206ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5216ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 5228383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public BaseRecipientAdapter(Context context, int preferredMaxResultCount) { 52380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this(context, preferredMaxResultCount, QUERY_TYPE_EMAIL); 52480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 52580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 52680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public BaseRecipientAdapter(int queryMode, Context context) { 52780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this(context, DEFAULT_PREFERRED_MAX_RESULT_COUNT, queryMode); 52880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 52980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 53080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public BaseRecipientAdapter(int queryMode, Context context, int preferredMaxResultCount) { 53180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this(context, preferredMaxResultCount, queryMode); 53280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 53380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 53480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public BaseRecipientAdapter(Context context, int preferredMaxResultCount, int queryMode) { 5356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mContext = context; 5366ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mContentResolver = context.getContentResolver(); 5376ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mPreferredMaxResultCount = preferredMaxResultCount; 5388af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein mPhotoManager = new DefaultPhotoManager(mContentResolver); 53980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor mQueryType = queryMode; 54080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 54180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (queryMode == QUERY_TYPE_EMAIL) { 5421db635b5a09c77a27fe17a9ce31c21a67458c2bcAndrew Sapperstein mQueryMode = Queries.EMAIL; 54380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else if (queryMode == QUERY_TYPE_PHONE) { 5441db635b5a09c77a27fe17a9ce31c21a67458c2bcAndrew Sapperstein mQueryMode = Queries.PHONE; 54580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else { 5461db635b5a09c77a27fe17a9ce31c21a67458c2bcAndrew Sapperstein mQueryMode = Queries.EMAIL; 54780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Log.e(TAG, "Unsupported query type: " + queryMode); 54880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 54980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 55080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 55176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert public Context getContext() { 55276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert return mContext; 55376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 55476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert 55580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public int getQueryType() { 55680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor return mQueryType; 5576ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5586ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 559b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public void setDropdownChipLayouter(DropdownChipLayouter dropdownChipLayouter) { 560b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin mDropdownChipLayouter = dropdownChipLayouter; 5611db635b5a09c77a27fe17a9ce31c21a67458c2bcAndrew Sapperstein mDropdownChipLayouter.setQuery(mQueryMode); 562b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 563b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 564b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public DropdownChipLayouter getDropdownChipLayouter() { 565b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return mDropdownChipLayouter; 566b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 567b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 5686ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 5698af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * Enables overriding the default photo manager that is used. 5708af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein */ 5718af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein public void setPhotoManager(PhotoManager photoManager) { 5728af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein mPhotoManager = photoManager; 5738af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 5748af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 5758af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein public PhotoManager getPhotoManager() { 5768af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein return mPhotoManager; 5778af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 5788af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 5798af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein /** 5808af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * If true, forces using the {@link com.android.ex.chips.SingleRecipientArrayAdapter} 5818af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * instead of {@link com.android.ex.chips.RecipientAlternatesAdapter} when 5828af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * clicking on a chip. Default implementation returns {@code false}. 5838af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein */ 5848af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein public boolean forceShowAddress() { 5858af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein return false; 5868af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 5878af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 5888af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein /** 5898af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * Used to replace email addresses with chips. Default behavior 5908af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * queries the ContactsProvider for contact information about the contact. 5918af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * Derived classes should override this method if they wish to use a 5928af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * new data source. 5938af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * @param inAddresses addresses to query 5948af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * @param callback callback to return results in case of success or failure 5958af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein */ 5968af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein public void getMatchingRecipients(ArrayList<String> inAddresses, 5978af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein RecipientAlternatesAdapter.RecipientMatchCallback callback) { 5988af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein RecipientAlternatesAdapter.getMatchingRecipients( 5998af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein getContext(), this, inAddresses, getAccount(), callback); 6008af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 6018af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 6028af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein /** 6036ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Set the account when known. Causes the search to prioritize contacts from that account. 6046ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 605dfd7e0774f9a4f47c127b21e5468430374340f66Andy Huang @Override 6066ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public void setAccount(Account account) { 6076ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mAccount = account; 6086ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6096ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6106ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** Will be called from {@link AutoCompleteTextView} to prepare auto-complete list. */ 6116ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 6126ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public Filter getFilter() { 6136ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return new DefaultFilter(); 6146ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6156ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 61676f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert /** 6178af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * An extension to {@link RecipientAlternatesAdapter#getMatchingRecipients} that allows 61876f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert * additional sources of contacts to be considered as matching recipients. 61976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert * @param addresses A set of addresses to be matched 62076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert * @return A list of matches or null if none found 62176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert */ 62276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert public Map<String, RecipientEntry> getMatchingRecipients(Set<String> addresses) { 62376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert return null; 62476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 62576f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert 62616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp public static List<DirectorySearchParams> setupOtherDirectories(Context context, 62716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Cursor directoryCursor, Account account) { 62816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp final PackageManager packageManager = context.getPackageManager(); 62974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final List<DirectorySearchParams> paramsList = new ArrayList<DirectorySearchParams>(); 6306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa DirectorySearchParams preferredDirectory = null; 6316ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa while (directoryCursor.moveToNext()) { 6326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final long id = directoryCursor.getLong(DirectoryListQuery.ID); 6336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // Skip the local invisible directory, because the default directory already includes 6356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // all local results. 6366ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (id == Directory.LOCAL_INVISIBLE) { 6376ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa continue; 6386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6406ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final DirectorySearchParams params = new DirectorySearchParams(); 6416ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final String packageName = directoryCursor.getString(DirectoryListQuery.PACKAGE_NAME); 6426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final int resourceId = directoryCursor.getInt(DirectoryListQuery.TYPE_RESOURCE_ID); 6436ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.directoryId = id; 6446ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.displayName = directoryCursor.getString(DirectoryListQuery.DISPLAY_NAME); 6456ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.accountName = directoryCursor.getString(DirectoryListQuery.ACCOUNT_NAME); 6466ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.accountType = directoryCursor.getString(DirectoryListQuery.ACCOUNT_TYPE); 6476ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (packageName != null && resourceId != 0) { 6486ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa try { 6496ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final Resources resources = 6506ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa packageManager.getResourcesForApplication(packageName); 6516ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.directoryType = resources.getString(resourceId); 6526ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (params.directoryType == null) { 6536ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Log.e(TAG, "Cannot resolve directory name: " 6546ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa + resourceId + "@" + packageName); 6556ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6566ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } catch (NameNotFoundException e) { 6576ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Log.e(TAG, "Cannot resolve directory name: " 6586ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa + resourceId + "@" + packageName, e); 6596ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6606ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6616ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6626ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // If an account has been provided and we found a directory that 6636ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // corresponds to that account, place that directory second, directly 6646ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // underneath the local contacts. 66516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (account != null && account.name.equals(params.accountName) && 66616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp account.type.equals(params.accountType)) { 6676ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa preferredDirectory = params; 6686ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } else { 66974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa paramsList.add(params); 6706ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6716ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6726ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6736ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (preferredDirectory != null) { 67474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa paramsList.add(1, preferredDirectory); 6756ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6766ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 67774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa return paramsList; 6786ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6796ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6806ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 6818383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * Starts search in other directories using {@link Filter}. Results will be handled in 6828383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link DirectoryFilter}. 6836ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 68476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert protected void startSearchOtherDirectories( 68574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa CharSequence constraint, List<DirectorySearchParams> paramsList, int limit) { 68674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final int count = paramsList.size(); 6876ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // Note: skipping the default partition (index 0), which has already been loaded 6886ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa for (int i = 1; i < count; i++) { 68974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final DirectorySearchParams params = paramsList.get(i); 69074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.constraint = constraint; 69174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (params.filter == null) { 69274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.filter = new DirectoryFilter(params); 69374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 69474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.filter.setLimit(limit); 69574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.filter.filter(constraint); 69674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 6974bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 6988383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Directory search started. We may show "waiting" message if directory results are slow 6998383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // enough. 7004bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa mRemainingDirectoryCount = count - 1; 7014bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa mDelayedMessageHandler.sendDelayedLoadMessage(); 70274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 70374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 7048af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein /** 7058af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * Called whenever {@link com.android.ex.chips.BaseRecipientAdapter.DirectoryFilter} 7068af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * wants to add an additional entry to the results. Derived classes should override 7078af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * this method if they are not using the default data structures provided by 7088af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * {@link com.android.ex.chips.BaseRecipientAdapter} and are instead using their 7098af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * own data structures to store and collate data. 7108af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * @param entry the entry being added 7118af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * @param isAggregatedEntry 7128af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein */ 7138af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein protected void putOneEntry(TemporaryEntry entry, boolean isAggregatedEntry) { 7148af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein putOneEntry(entry, isAggregatedEntry, 7158af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein mEntryMap, mNonAggregatedEntries, mExistingDestinations); 7168af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 7178af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 718f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy private static void putOneEntry(TemporaryEntry entry, boolean isAggregatedEntry, 7198383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa LinkedHashMap<Long, List<RecipientEntry>> entryMap, 7208383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa List<RecipientEntry> nonAggregatedEntries, 7218383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Set<String> existingDestinations) { 7228383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (existingDestinations.contains(entry.destination)) { 7238383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa return; 7248383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 72574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 7268383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa existingDestinations.add(entry.destination); 7278383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 7288383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (!isAggregatedEntry) { 7298383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa nonAggregatedEntries.add(RecipientEntry.constructTopLevelEntry( 7307211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.displayName, 73100adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki entry.displayNameSource, 7327211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.destination, entry.destinationType, entry.destinationLabel, 7337a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy entry.contactId, entry.directoryId, entry.dataId, entry.thumbnailUriString, 7347a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy true, entry.lookupKey)); 7358383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } else if (entryMap.containsKey(entry.contactId)) { 7368383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // We already have a section for the person. 7378383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final List<RecipientEntry> entryList = entryMap.get(entry.contactId); 7388383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entryList.add(RecipientEntry.constructSecondLevelEntry( 7397211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.displayName, 74000adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki entry.displayNameSource, 7417211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.destination, entry.destinationType, entry.destinationLabel, 7427a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy entry.contactId, entry.directoryId, entry.dataId, entry.thumbnailUriString, 7437a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy true, entry.lookupKey)); 7448383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } else { 7458383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final List<RecipientEntry> entryList = new ArrayList<RecipientEntry>(); 7468383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entryList.add(RecipientEntry.constructTopLevelEntry( 7477211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.displayName, 74800adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki entry.displayNameSource, 7497211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.destination, entry.destinationType, entry.destinationLabel, 7507a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy entry.contactId, entry.directoryId, entry.dataId, entry.thumbnailUriString, 7517a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy true, entry.lookupKey)); 7528383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entryMap.put(entry.contactId, entryList); 7536ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 7546ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 7556ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 7566ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 7578af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * Returns the actual list to use for this Adapter. Derived classes 7588af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * should override this method if overriding how the adapter stores and collates 7598af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein * data. 7608af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein */ 7618af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein protected List<RecipientEntry> constructEntryList() { 7628af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein return constructEntryList(mEntryMap, mNonAggregatedEntries); 7638af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 7648af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 7658af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein /** 76674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * Constructs an actual list for this Adapter using {@link #mEntryMap}. Also tries to 76774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * fetch a cached photo for each contact entry (other than separators), or request another 7688383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * thread to get one from directories. 7696ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 7708383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private List<RecipientEntry> constructEntryList( 7718383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa LinkedHashMap<Long, List<RecipientEntry>> entryMap, 772f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy List<RecipientEntry> nonAggregatedEntries) { 7738383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final List<RecipientEntry> entries = new ArrayList<RecipientEntry>(); 77474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa int validEntryCount = 0; 7758383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa for (Map.Entry<Long, List<RecipientEntry>> mapEntry : entryMap.entrySet()) { 776f621a601e1f966c89b7aadbcca384021e14d668dMindy Pereira final List<RecipientEntry> entryList = mapEntry.getValue(); 7776ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final int size = entryList.size(); 7786ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa for (int i = 0; i < size; i++) { 779f621a601e1f966c89b7aadbcca384021e14d668dMindy Pereira RecipientEntry entry = entryList.get(i); 7808383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entries.add(entry); 7818af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein mPhotoManager.populatePhotoBytesAsync(entry, this); 78274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa validEntryCount++; 7836ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 78474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (validEntryCount > mPreferredMaxResultCount) { 78574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa break; 78674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 7876ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 78874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (validEntryCount <= mPreferredMaxResultCount) { 7898383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa for (RecipientEntry entry : nonAggregatedEntries) { 79074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (validEntryCount > mPreferredMaxResultCount) { 79174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa break; 79274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 7938383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entries.add(entry); 7948af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein mPhotoManager.populatePhotoBytesAsync(entry, this); 79574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa validEntryCount++; 79674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 79774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 79874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 7998383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa return entries; 8008383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 8018383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 8028c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp 80338fe984ca3e9ed7af3d5441ee3a7e82dbfdb3d2cMike Schneider public interface EntriesUpdatedObserver { 8048c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp public void onChanged(List<RecipientEntry> entries); 8058c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp } 8068c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp 8078c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp public void registerUpdateObserver(EntriesUpdatedObserver observer) { 8088c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp mEntriesUpdatedObserver = observer; 8098c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp } 8108c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp 8118383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa /** Resets {@link #mEntries} and notify the event to its parent ListView. */ 8128af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein protected void updateEntries(List<RecipientEntry> newEntries) { 8138383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mEntries = newEntries; 8148c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp mEntriesUpdatedObserver.onChanged(newEntries); 8156ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa notifyDataSetChanged(); 8166ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 8176ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 81831c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao /** 81931c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao * If there are no local results and we are searching alternate results, 82031c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao * in the new result set, cache off what had been shown to the user for use until 82131c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao * the first directory result is returned 82231c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao * @param newEntryCount number of newly loaded entries 82331c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao * @param paramListCount number of alternate filters it will search (including the current one). 82431c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao */ 82531c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao protected void cacheCurrentEntriesIfNeeded(int newEntryCount, int paramListCount) { 82631c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao if (newEntryCount == 0 && paramListCount > 1) { 82731c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao cacheCurrentEntries(); 82831c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao } 82931c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao } 83031c33ef87cb0612250b812233ffbc0c46e88a371Jin Cao 8318af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein protected void cacheCurrentEntries() { 83237726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook mTempEntries = mEntries; 83337726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook } 83437726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 8358af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein protected void clearTempEntries() { 83637726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook mTempEntries = null; 83737726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook } 83837726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 83976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert protected List<RecipientEntry> getEntries() { 84037726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook return mTempEntries != null ? mTempEntries : mEntries; 84137726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook } 84237726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 84335e82d4f9522906f7953667cf5c5f8137ec2f5acJin Cao protected void fetchPhoto(final RecipientEntry entry, PhotoManager.PhotoManagerCallback cb) { 84435e82d4f9522906f7953667cf5c5f8137ec2f5acJin Cao mPhotoManager.populatePhotoBytesAsync(entry, cb); 8456b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira } 8466b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira 847d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa private Cursor doQuery(CharSequence constraint, int limit, Long directoryId) { 8481db635b5a09c77a27fe17a9ce31c21a67458c2bcAndrew Sapperstein final Uri.Builder builder = mQueryMode.getContentFilterUri().buildUpon() 8498383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa .appendPath(constraint.toString()) 8508383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, 8518383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa String.valueOf(limit + ALLOWANCE_FOR_DUPLICATES)); 8528383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (directoryId != null) { 8538383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 8548383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa String.valueOf(directoryId)); 8558383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 8568383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (mAccount != null) { 8578383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa builder.appendQueryParameter(PRIMARY_ACCOUNT_NAME, mAccount.name); 8588383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa builder.appendQueryParameter(PRIMARY_ACCOUNT_TYPE, mAccount.type); 8598383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 8608383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final long start = System.currentTimeMillis(); 8618383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final Cursor cursor = mContentResolver.query( 8621db635b5a09c77a27fe17a9ce31c21a67458c2bcAndrew Sapperstein builder.build(), mQueryMode.getProjection(), null, null, null); 8638383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final long end = System.currentTimeMillis(); 8648383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 8658383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.d(TAG, "Time for autocomplete (query: " + constraint 8668383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + ", directoryId: " + directoryId + ", num_of_results: " 8678383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + (cursor != null ? cursor.getCount() : "null") + "): " 8688383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + (end - start) + " ms"); 869d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 870d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa return cursor; 871d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 872d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa 873cc20880f80a3a6f6e4aaef4547ed088d9364e741Daisuke Miyakawa // TODO: This won't be used at all. We should find better way to quit the thread.. 874cc20880f80a3a6f6e4aaef4547ed088d9364e741Daisuke Miyakawa /*public void close() { 8758383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mEntries = null; 87674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mPhotoCacheMap.evictAll(); 877cc20880f80a3a6f6e4aaef4547ed088d9364e741Daisuke Miyakawa if (!sPhotoHandlerThread.quit()) { 87874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa Log.w(TAG, "Failed to quit photo handler thread, ignoring it."); 87974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 880cc20880f80a3a6f6e4aaef4547ed088d9364e741Daisuke Miyakawa }*/ 8816ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 8826ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 8836ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public int getCount() { 88437726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook final List<RecipientEntry> entries = getEntries(); 88537726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook return entries != null ? entries.size() : 0; 8866ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 8876ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 8886ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 889858e094f1c695aefdf6a23f522c0f16d81bd79f7Scott Kennedy public RecipientEntry getItem(int position) { 89037726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook return getEntries().get(position); 8916ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 8926ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 8936ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 8946ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public long getItemId(int position) { 8956ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return position; 8966ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 8976ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 8986ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 89974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public int getViewTypeCount() { 900f621a601e1f966c89b7aadbcca384021e14d668dMindy Pereira return RecipientEntry.ENTRY_TYPE_SIZE; 90174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 90274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 90374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa @Override 90474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public int getItemViewType(int position) { 90537726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook return getEntries().get(position).getEntryType(); 90674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 9076ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 90874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa @Override 9096d6bd68a492fbbfca50ae4793313083105e6f270Daisuke Miyakawa public boolean isEnabled(int position) { 91037726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook return getEntries().get(position).isSelectable(); 9116d6bd68a492fbbfca50ae4793313083105e6f270Daisuke Miyakawa } 9126d6bd68a492fbbfca50ae4793313083105e6f270Daisuke Miyakawa 9136d6bd68a492fbbfca50ae4793313083105e6f270Daisuke Miyakawa @Override 91474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public View getView(int position, View convertView, ViewGroup parent) { 91537726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook final RecipientEntry entry = getEntries().get(position); 9166ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 917d5ce95bdc1ab57d91cc5408fda49d23d9630da37Kevin Lin final String constraint = mCurrentConstraint == null ? null : 918d5ce95bdc1ab57d91cc5408fda49d23d9630da37Kevin Lin mCurrentConstraint.toString(); 919d5ce95bdc1ab57d91cc5408fda49d23d9630da37Kevin Lin 920b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return mDropdownChipLayouter.bindView(convertView, parent, entry, position, 921d5ce95bdc1ab57d91cc5408fda49d23d9630da37Kevin Lin AdapterType.BASE_RECIPIENT, constraint); 922d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 92316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 92416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp public Account getAccount() { 92516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp return mAccount; 92616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 9278af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 9288af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein @Override 92950429c51adbd79c5d7dd5beb2c267daf9465f20fAndrew Sapperstein public void onPhotoBytesPopulated() { 93050429c51adbd79c5d7dd5beb2c267daf9465f20fAndrew Sapperstein // Default implementation does nothing 93150429c51adbd79c5d7dd5beb2c267daf9465f20fAndrew Sapperstein } 93250429c51adbd79c5d7dd5beb2c267daf9465f20fAndrew Sapperstein 93350429c51adbd79c5d7dd5beb2c267daf9465f20fAndrew Sapperstein @Override 9348af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein public void onPhotoBytesAsynchronouslyPopulated() { 9358af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein notifyDataSetChanged(); 9368af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 9370efdc53cd0d040c1a27a7d39003916e54e284be2Jin Cao 9380efdc53cd0d040c1a27a7d39003916e54e284be2Jin Cao @Override 9390efdc53cd0d040c1a27a7d39003916e54e284be2Jin Cao public void onPhotoBytesAsyncLoadFailed() { 94050429c51adbd79c5d7dd5beb2c267daf9465f20fAndrew Sapperstein // Default implementation does nothing 9410efdc53cd0d040c1a27a7d39003916e54e284be2Jin Cao } 9426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa} 943