BaseRecipientAdapter.java revision b10d1c652d0416c284d9792fc9a0a92b3acd51ca
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; 2734f5320d620877f757ed78a6e37754bbeabee5aaDaisuke Miyakawaimport android.os.AsyncTask; 286ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.os.Handler; 294bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawaimport android.os.Message; 306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.provider.ContactsContract; 3174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Photo; 326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.provider.ContactsContract.Directory; 331650ef6bb75ba88340cc59d22b2578c0f460b4f1Scott Kennedyimport android.support.v4.util.LruCache; 346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.text.TextUtils; 356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.text.util.Rfc822Token; 366ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.util.Log; 37d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawaimport android.view.LayoutInflater; 386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.view.View; 396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.view.ViewGroup; 406ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.AutoCompleteTextView; 416ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.BaseAdapter; 426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.Filter; 436ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport android.widget.Filterable; 44b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 45b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport com.android.ex.chips.DropdownChipLayouter.AdapterType; 466ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 47c88702e49917a21b9753d587800de25f87f2c5a8Jay Shraunerimport java.io.ByteArrayOutputStream; 48c88702e49917a21b9753d587800de25f87f2c5a8Jay Shraunerimport java.io.IOException; 49b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport java.io.InputStream; 506ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport java.util.ArrayList; 5174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawaimport java.util.HashSet; 52cf9337aa4b2d844f4941d75832f52266c4fc3fa7Daisuke Miyakawaimport java.util.LinkedHashMap; 536ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport java.util.List; 546ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawaimport java.util.Map; 5574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawaimport java.util.Set; 566ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 576ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa/** 586ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Adapter for showing a recipient list. 596ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 60df4457285cf0a54d957f1fad3bbc07112f750818Mindy Pereirapublic abstract class BaseRecipientAdapter extends BaseAdapter implements Filterable, 61941187c70e06e977eb80f3ccaccd421148faadaeMindy Pereira AccountSpecifier { 626ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private static final String TAG = "BaseRecipientAdapter"; 638383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 646b616f1d06b092825da345078ce4a899b829290dDaisuke Miyakawa private static final boolean DEBUG = false; 656ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 666ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 676ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * The preferred number of results to be retrieved. This number may be 686ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * exceeded if there are several directories configured, because we will use 696ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * the same limit for all directories. 706ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 716ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private static final int DEFAULT_PREFERRED_MAX_RESULT_COUNT = 10; 726ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 736ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 746ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * The number of extra entries requested to allow for duplicates. Duplicates 756ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * are removed from the overall result. 766ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 7716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp static final int ALLOWANCE_FOR_DUPLICATES = 5; 786ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 797537f840506bcb642bed9dc1c2bdcf6d31c6b2a7Daisuke Miyakawa // This is ContactsContract.PRIMARY_ACCOUNT_NAME. Available from ICS as hidden 8016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp static final String PRIMARY_ACCOUNT_NAME = "name_for_primary_account"; 817537f840506bcb642bed9dc1c2bdcf6d31c6b2a7Daisuke Miyakawa // This is ContactsContract.PRIMARY_ACCOUNT_TYPE. Available from ICS as hidden 8216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp static final String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account"; 837537f840506bcb642bed9dc1c2bdcf6d31c6b2a7Daisuke Miyakawa 8474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa /** The number of photos cached in this Adapter. */ 8574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private static final int PHOTO_CACHE_SIZE = 20; 8674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 874bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa /** 884bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * The "Waiting for more contacts" message will be displayed if search is not complete 894bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * within this many milliseconds. 904bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa */ 914bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa private static final int MESSAGE_SEARCH_PENDING_DELAY = 1000; 924bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa /** Used to prepare "Waiting for more contacts" message. */ 934bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa private static final int MESSAGE_SEARCH_PENDING = 1; 944bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 95d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public static final int QUERY_TYPE_EMAIL = 0; 96d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa public static final int QUERY_TYPE_PHONE = 1; 97d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa 9880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor private final Queries.Query mQuery; 9980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor private final int mQueryType; 10080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 1016ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 1026ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Model object for a {@link Directory} row. 1036ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 1046ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public final static class DirectorySearchParams { 1056ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public long directoryId; 1066ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String directoryType; 1076ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String displayName; 1086ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String accountName; 1096ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public String accountType; 1106ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public CharSequence constraint; 1116ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public DirectoryFilter filter; 1126ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1136ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 11474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private static class PhotoQuery { 11574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public static final String[] PROJECTION = { 11674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa Photo.PHOTO 11774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa }; 11874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 11974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public static final int PHOTO = 0; 12074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 12174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 12216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp protected static class DirectoryListQuery { 1236ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1246ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final Uri URI = 1256ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "directories"); 1266ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final String[] PROJECTION = { 1276ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory._ID, // 0 1286ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.ACCOUNT_NAME, // 1 1296ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.ACCOUNT_TYPE, // 2 1306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.DISPLAY_NAME, // 3 1316ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.PACKAGE_NAME, // 4 1326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Directory.TYPE_RESOURCE_ID, // 5 1336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa }; 1346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int ID = 0; 1366ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int ACCOUNT_NAME = 1; 1376ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int ACCOUNT_TYPE = 2; 1386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int DISPLAY_NAME = 3; 1396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int PACKAGE_NAME = 4; 1406ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public static final int TYPE_RESOURCE_ID = 5; 1416ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 1426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 1438383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa /** Used to temporarily hold results in Cursor objects. */ 14476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert protected static class TemporaryEntry { 1458383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final String displayName; 1468383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final String destination; 1477211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa public final int destinationType; 1487211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa public final String destinationLabel; 1498383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final long contactId; 1508383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final long dataId; 1518383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final String thumbnailUriString; 15200adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki public final int displayNameSource; 153514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy public final boolean isGalContact; 1548383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 15576f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert public TemporaryEntry( 15676f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert String displayName, 15776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert String destination, 15876f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert int destinationType, 15976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert String destinationLabel, 16076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert long contactId, 16176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert long dataId, 16276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert String thumbnailUriString, 163514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy int displayNameSource, 164514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy boolean isGalContact) { 16576f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.displayName = displayName; 16676f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.destination = destination; 16776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.destinationType = destinationType; 16876f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.destinationLabel = destinationLabel; 16976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.contactId = contactId; 17076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.dataId = dataId; 17176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.thumbnailUriString = thumbnailUriString; 17276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert this.displayNameSource = displayNameSource; 173514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy this.isGalContact = isGalContact; 17476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 17576f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert 176514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy public TemporaryEntry(Cursor cursor, boolean isGalContact) { 17780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.displayName = cursor.getString(Queries.Query.NAME); 17880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.destination = cursor.getString(Queries.Query.DESTINATION); 17980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.destinationType = cursor.getInt(Queries.Query.DESTINATION_TYPE); 18080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.destinationLabel = cursor.getString(Queries.Query.DESTINATION_LABEL); 18180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.contactId = cursor.getLong(Queries.Query.CONTACT_ID); 18280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.dataId = cursor.getLong(Queries.Query.DATA_ID); 18380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this.thumbnailUriString = cursor.getString(Queries.Query.PHOTO_THUMBNAIL_URI); 18400adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki this.displayNameSource = cursor.getInt(Queries.Query.DISPLAY_NAME_SOURCE); 185514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy this.isGalContact = isGalContact; 1868383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 1878383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 1888383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 1898383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa /** 1908383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * Used to pass results from {@link DefaultFilter#performFiltering(CharSequence)} to 1918383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link DefaultFilter#publishResults(CharSequence, android.widget.Filter.FilterResults)} 1928383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa */ 1938383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private static class DefaultFilterResult { 1948383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final List<RecipientEntry> entries; 1958383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final LinkedHashMap<Long, List<RecipientEntry>> entryMap; 1968383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final List<RecipientEntry> nonAggregatedEntries; 1978383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final Set<String> existingDestinations; 1988383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public final List<DirectorySearchParams> paramsList; 1998383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2008383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public DefaultFilterResult(List<RecipientEntry> entries, 2018383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa LinkedHashMap<Long, List<RecipientEntry>> entryMap, 2028383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa List<RecipientEntry> nonAggregatedEntries, 2038383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Set<String> existingDestinations, 2048383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa List<DirectorySearchParams> paramsList) { 2058383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa this.entries = entries; 2068383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa this.entryMap = entryMap; 2078383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa this.nonAggregatedEntries = nonAggregatedEntries; 2088383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa this.existingDestinations = existingDestinations; 2098383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa this.paramsList = paramsList; 2108383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2118383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2128383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2136ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 2146ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * An asynchronous filter used for loading two data sets: email rows from the local 2156ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * contact provider and the list of {@link Directory}'s. 2166ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 2176ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private final class DefaultFilter extends Filter { 2186ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2196ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 2206ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected FilterResults performFiltering(CharSequence constraint) { 2218383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 2228383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.d(TAG, "start filtering. constraint: " + constraint + ", thread:" 2238383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + Thread.currentThread()); 2248383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2258383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 22674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final FilterResults results = new FilterResults(); 2278383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Cursor defaultDirectoryCursor = null; 2288383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Cursor directoryCursor = null; 2298383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2308383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (TextUtils.isEmpty(constraint)) { 23137726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook clearTempEntries(); 2328383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Return empty results. 2338383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa return results; 2346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2368383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa try { 2378383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa defaultDirectoryCursor = doQuery(constraint, mPreferredMaxResultCount, null); 23880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 2398383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (defaultDirectoryCursor == null) { 2408383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 2418383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.w(TAG, "null cursor returned for default Email filter query."); 2428383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2438383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } else { 2448383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // These variables will become mEntries, mEntryMap, mNonAggregatedEntries, and 2458383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // mExistingDestinations. Here we shouldn't use those member variables directly 2468383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // since this method is run outside the UI thread. 2478383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final LinkedHashMap<Long, List<RecipientEntry>> entryMap = 2488383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa new LinkedHashMap<Long, List<RecipientEntry>>(); 2498383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final List<RecipientEntry> nonAggregatedEntries = 2508383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa new ArrayList<RecipientEntry>(); 2518383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final Set<String> existingDestinations = new HashSet<String>(); 2528383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2538383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa while (defaultDirectoryCursor.moveToNext()) { 2548383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Note: At this point each entry doesn't contain any photo 2558383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // (thus getPhotoBytes() returns null). 256514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy putOneEntry(new TemporaryEntry(defaultDirectoryCursor, 257514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy false /* isGalContact */), 2588383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa true, entryMap, nonAggregatedEntries, existingDestinations); 2598383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2608383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2618383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // We'll copy this result to mEntry in publicResults() (run in the UX thread). 262f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy final List<RecipientEntry> entries = constructEntryList( 263f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy entryMap, nonAggregatedEntries); 2648383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 2658383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // After having local results, check the size of results. If the results are 2668383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // not enough, we search remote directories, which will take longer time. 2678383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final int limit = mPreferredMaxResultCount - existingDestinations.size(); 2688383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final List<DirectorySearchParams> paramsList; 2698383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (limit > 0) { 2708383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 2718383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.d(TAG, "More entries should be needed (current: " 2728383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + existingDestinations.size() 2738383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + ", remaining limit: " + limit + ") "); 2748383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2758383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa directoryCursor = mContentResolver.query( 2768383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa DirectoryListQuery.URI, DirectoryListQuery.PROJECTION, 2778383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa null, null, null); 27816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp paramsList = setupOtherDirectories(mContext, directoryCursor, mAccount); 2798383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } else { 2808383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // We don't need to search other directories. 2818383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa paramsList = null; 2828383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2836ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 2848383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.values = new DefaultFilterResult( 2858383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entries, entryMap, nonAggregatedEntries, 2868383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa existingDestinations, paramsList); 2878383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.count = 1; 2888383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2898383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } finally { 2908383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (defaultDirectoryCursor != null) { 2918383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa defaultDirectoryCursor.close(); 2928383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 2938383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (directoryCursor != null) { 2948383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa directoryCursor.close(); 2958383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 29674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 2976ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return results; 2986ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 2996ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3006ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 3016ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected void publishResults(final CharSequence constraint, FilterResults results) { 3028383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // If a user types a string very quickly and database is slow, "constraint" refers to 3038383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // an older text which shows inconsistent results for users obsolete (b/4998713). 3048383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // TODO: Fix it. 3058383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mCurrentConstraint = constraint; 3068383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 30737726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook clearTempEntries(); 30837726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 3096ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (results.values != null) { 3108383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa DefaultFilterResult defaultFilterResult = (DefaultFilterResult) results.values; 3118383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mEntryMap = defaultFilterResult.entryMap; 3128383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mNonAggregatedEntries = defaultFilterResult.nonAggregatedEntries; 3138383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mExistingDestinations = defaultFilterResult.existingDestinations; 3148383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 31537726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook // If there are no local results, in the new result set, cache off what had been 31637726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook // shown to the user for use until the first directory result is returned 31737726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook if (defaultFilterResult.entries.size() == 0 && 31837726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook defaultFilterResult.paramsList != null) { 31937726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook cacheCurrentEntries(); 32037726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook } 32137726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 3228383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa updateEntries(defaultFilterResult.entries); 3238383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 3248383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // We need to search other remote directories, doing other Filter requests. 3258383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (defaultFilterResult.paramsList != null) { 3268383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final int limit = mPreferredMaxResultCount - 3278383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa defaultFilterResult.existingDestinations.size(); 3288383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa startSearchOtherDirectories(constraint, defaultFilterResult.paramsList, limit); 3298383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 3306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3318383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 3326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 3356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public CharSequence convertResultToString(Object resultValue) { 336f621a601e1f966c89b7aadbcca384021e14d668dMindy Pereira final RecipientEntry entry = (RecipientEntry)resultValue; 3376ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final String displayName = entry.getDisplayName(); 3386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final String emailAddress = entry.getDestination(); 3396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, emailAddress)) { 3406ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return emailAddress; 3416ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } else { 3426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return new Rfc822Token(displayName, emailAddress, null).toString(); 3436ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3446ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3456ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3466ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3476ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 3486ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * An asynchronous filter that performs search in a particular directory. 3496ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 35076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert protected class DirectoryFilter extends Filter { 35174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final DirectorySearchParams mParams; 3526ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private int mLimit; 3536ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 35474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public DirectoryFilter(DirectorySearchParams params) { 3558383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mParams = params; 3566ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3576ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3586ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public synchronized void setLimit(int limit) { 3596ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa this.mLimit = limit; 3606ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3616ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3626ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public synchronized int getLimit() { 3636ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return this.mLimit; 3646ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 3656ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 3666ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 3676ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected FilterResults performFiltering(CharSequence constraint) { 3688383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 3698383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.d(TAG, "DirectoryFilter#performFiltering. directoryId: " + mParams.directoryId 3708383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + ", constraint: " + constraint + ", thread: " + Thread.currentThread()); 3718383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 37274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final FilterResults results = new FilterResults(); 3738383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.values = null; 3748383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.count = 0; 3758383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 3766ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (!TextUtils.isEmpty(constraint)) { 3778383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final ArrayList<TemporaryEntry> tempEntries = new ArrayList<TemporaryEntry>(); 3788383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 3798383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Cursor cursor = null; 3808383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa try { 3818383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // We don't want to pass this Cursor object to UI thread (b/5017608). 3828383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Assuming the result should contain fairly small results (at most ~10), 3838383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // We just copy everything to local structure. 3848383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa cursor = doQuery(constraint, getLimit(), mParams.directoryId); 38580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 3868383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (cursor != null) { 3878383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa while (cursor.moveToNext()) { 388514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy tempEntries.add(new TemporaryEntry(cursor, true /* isGalContact */)); 3898383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 3908383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 3918383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } finally { 3928383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (cursor != null) { 3938383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa cursor.close(); 3948383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 39574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 3968383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (!tempEntries.isEmpty()) { 3978383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.values = tempEntries; 3988383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa results.count = 1; 3998383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4008383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4018383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 4028383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 4038383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.v(TAG, "finished loading directory \"" + mParams.displayName + "\"" + 4048383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa " with query " + constraint); 4056ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4066ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 4076ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return results; 4086ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4096ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 4106ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 4116ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa protected void publishResults(final CharSequence constraint, FilterResults results) { 4128383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 4138383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.d(TAG, "DirectoryFilter#publishResult. constraint: " + constraint 4148383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + ", mCurrentConstraint: " + mCurrentConstraint); 4158383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4168383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mDelayedMessageHandler.removeDelayedLoadMessage(); 4178383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Check if the received result matches the current constraint 4188383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // If not - the user must have continued typing after the request was issued, which 4198383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // means several member variables (like mRemainingDirectoryLoad) are already 4208383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // overwritten so shouldn't be touched here anymore. 4218383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (TextUtils.equals(constraint, mCurrentConstraint)) { 4228383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (results.count > 0) { 423dfd7e0774f9a4f47c127b21e5468430374340f66Andy Huang @SuppressWarnings("unchecked") 4248383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final ArrayList<TemporaryEntry> tempEntries = 4258383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa (ArrayList<TemporaryEntry>) results.values; 4268383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 4278383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa for (TemporaryEntry tempEntry : tempEntries) { 4288383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa putOneEntry(tempEntry, mParams.directoryId == Directory.DEFAULT, 4298383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mEntryMap, mNonAggregatedEntries, mExistingDestinations); 4308383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4318383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4328383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 4338383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // If there are remaining directories, set up delayed message again. 4348383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mRemainingDirectoryCount--; 4358383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (mRemainingDirectoryCount > 0) { 4368383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 4378383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.d(TAG, "Resend delayed load message. Current mRemainingDirectoryLoad: " 4388383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + mRemainingDirectoryCount); 4398383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4408383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mDelayedMessageHandler.sendDelayedLoadMessage(); 4418383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 44237726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 44337726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook // If this directory result has some items, or there are no more directories that 44437726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook // we are waiting for, clear the temp results 44537726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook if (results.count > 0 || mRemainingDirectoryCount == 0) { 44637726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook // Clear the temp entries 44737726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook clearTempEntries(); 44837726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook } 4498383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 4508383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 4518383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Show the list again without "waiting" message. 452f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy updateEntries(constructEntryList(mEntryMap, mNonAggregatedEntries)); 4536ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4546ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 4556ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 45674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final Context mContext; 4576ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private final ContentResolver mContentResolver; 458d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa private final LayoutInflater mInflater; 4596ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa private Account mAccount; 46074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final int mPreferredMaxResultCount; 461b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin private DropdownChipLayouter mDropdownChipLayouter; 4626ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 4636ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 4648383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link #mEntries} is responsible for showing every result for this Adapter. To 4658383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * construct it, we use {@link #mEntryMap}, {@link #mNonAggregatedEntries}, and 4668383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link #mExistingDestinations}. 4678383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * 4688383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * First, each destination (an email address or a phone number) with a valid contactId is 4698383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * inserted into {@link #mEntryMap} and grouped by the contactId. Destinations without valid 4708383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * contactId (possible if they aren't in local storage) are stored in 4718383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link #mNonAggregatedEntries}. 47274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * Duplicates are removed using {@link #mExistingDestinations}. 47374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * 4748383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * After having all results from Cursor objects, all destinations in mEntryMap are copied to 4758383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link #mEntries}. If the number of destinations is not enough (i.e. less than 4768383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link #mPreferredMaxResultCount}), destinations in mNonAggregatedEntries are also used. 4778383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * 4788383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * These variables are only used in UI thread, thus should not be touched in 4798383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * performFiltering() methods. 4806ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 4818383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private LinkedHashMap<Long, List<RecipientEntry>> mEntryMap; 4828383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private List<RecipientEntry> mNonAggregatedEntries; 4838383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private Set<String> mExistingDestinations; 4848383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa /** Note: use {@link #updateEntries(List)} to update this variable. */ 4858383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private List<RecipientEntry> mEntries; 48637726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook private List<RecipientEntry> mTempEntries; 4876ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 4884bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa /** The number of directories this adapter is waiting for results. */ 4894bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa private int mRemainingDirectoryCount; 4904bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 49174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa /** 4928383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * Used to ignore asynchronous queries with a different constraint, which may happen when 49374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * users type characters quickly. 49474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa */ 49574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private CharSequence mCurrentConstraint; 49674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 49774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa private final LruCache<Uri, byte[]> mPhotoCacheMap; 4986ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 499d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa /** 5004bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * Handler specific for maintaining "Waiting for more contacts" message, which will be shown 5014bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * when: 5024bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * - there are directories to be searched 5034bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa * - results from directories are slow to come 5044bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa */ 5054bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa private final class DelayedMessageHandler extends Handler { 5064bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa @Override 5074bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa public void handleMessage(Message msg) { 5084bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa if (mRemainingDirectoryCount > 0) { 509f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy updateEntries(constructEntryList(mEntryMap, mNonAggregatedEntries)); 5104bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa } 5114bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa } 5124bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 5134bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa public void sendDelayedLoadMessage() { 5144bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa sendMessageDelayed(obtainMessage(MESSAGE_SEARCH_PENDING, 0, 0, null), 5154bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa MESSAGE_SEARCH_PENDING_DELAY); 5164bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa } 5174bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 5184bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa public void removeDelayedLoadMessage() { 5194bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa removeMessages(MESSAGE_SEARCH_PENDING); 5204bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa } 5214bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa } 5224bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 5234bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa private final DelayedMessageHandler mDelayedMessageHandler = new DelayedMessageHandler(); 5244bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 5258c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp private EntriesUpdatedObserver mEntriesUpdatedObserver; 5268c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp 5274bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa /** 528d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa * Constructor for email queries. 529d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa */ 5306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public BaseRecipientAdapter(Context context) { 53180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this(context, DEFAULT_PREFERRED_MAX_RESULT_COUNT, QUERY_TYPE_EMAIL); 5326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 5348383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa public BaseRecipientAdapter(Context context, int preferredMaxResultCount) { 53580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this(context, preferredMaxResultCount, QUERY_TYPE_EMAIL); 53680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 53780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 53880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public BaseRecipientAdapter(int queryMode, Context context) { 53980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this(context, DEFAULT_PREFERRED_MAX_RESULT_COUNT, queryMode); 54080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 54180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 54280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public BaseRecipientAdapter(int queryMode, Context context, int preferredMaxResultCount) { 54380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this(context, preferredMaxResultCount, queryMode); 54480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 54580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 54680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public BaseRecipientAdapter(Context context, int preferredMaxResultCount, int queryMode) { 5476ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mContext = context; 5486ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mContentResolver = context.getContentResolver(); 549d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa mInflater = LayoutInflater.from(context); 5506ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mPreferredMaxResultCount = preferredMaxResultCount; 55174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mPhotoCacheMap = new LruCache<Uri, byte[]>(PHOTO_CACHE_SIZE); 55280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor mQueryType = queryMode; 55380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 55480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (queryMode == QUERY_TYPE_EMAIL) { 55580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor mQuery = Queries.EMAIL; 55680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else if (queryMode == QUERY_TYPE_PHONE) { 55780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor mQuery = Queries.PHONE; 55880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else { 55980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor mQuery = Queries.EMAIL; 56080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Log.e(TAG, "Unsupported query type: " + queryMode); 56180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 56280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 56380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 56476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert public Context getContext() { 56576f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert return mContext; 56676f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 56776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert 56880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public int getQueryType() { 56980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor return mQueryType; 5706ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5716ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 572b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public void setDropdownChipLayouter(DropdownChipLayouter dropdownChipLayouter) { 573b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin mDropdownChipLayouter = dropdownChipLayouter; 574b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin mDropdownChipLayouter.setQuery(mQuery); 575b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 576b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 577b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public DropdownChipLayouter getDropdownChipLayouter() { 578b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return mDropdownChipLayouter; 579b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 580b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 5816ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 5826ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa * Set the account when known. Causes the search to prioritize contacts from that account. 5836ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 584dfd7e0774f9a4f47c127b21e5468430374340f66Andy Huang @Override 5856ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public void setAccount(Account account) { 5866ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa mAccount = account; 5876ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5886ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 5896ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** Will be called from {@link AutoCompleteTextView} to prepare auto-complete list. */ 5906ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 5916ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public Filter getFilter() { 5926ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return new DefaultFilter(); 5936ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 5946ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 59576f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert /** 59676f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert * An extesion to {@link RecipientAlternatesAdapter#getMatchingRecipients} that allows 59776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert * additional sources of contacts to be considered as matching recipients. 59876f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert * @param addresses A set of addresses to be matched 59976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert * @return A list of matches or null if none found 60076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert */ 60176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert public Map<String, RecipientEntry> getMatchingRecipients(Set<String> addresses) { 60276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert return null; 60376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 60476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert 60516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp public static List<DirectorySearchParams> setupOtherDirectories(Context context, 60616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Cursor directoryCursor, Account account) { 60716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp final PackageManager packageManager = context.getPackageManager(); 60874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final List<DirectorySearchParams> paramsList = new ArrayList<DirectorySearchParams>(); 6096ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa DirectorySearchParams preferredDirectory = null; 6106ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa while (directoryCursor.moveToNext()) { 6116ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final long id = directoryCursor.getLong(DirectoryListQuery.ID); 6126ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6136ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // Skip the local invisible directory, because the default directory already includes 6146ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // all local results. 6156ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (id == Directory.LOCAL_INVISIBLE) { 6166ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa continue; 6176ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6186ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6196ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final DirectorySearchParams params = new DirectorySearchParams(); 6206ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final String packageName = directoryCursor.getString(DirectoryListQuery.PACKAGE_NAME); 6216ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final int resourceId = directoryCursor.getInt(DirectoryListQuery.TYPE_RESOURCE_ID); 6226ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.directoryId = id; 6236ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.displayName = directoryCursor.getString(DirectoryListQuery.DISPLAY_NAME); 6246ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.accountName = directoryCursor.getString(DirectoryListQuery.ACCOUNT_NAME); 6256ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.accountType = directoryCursor.getString(DirectoryListQuery.ACCOUNT_TYPE); 6266ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (packageName != null && resourceId != 0) { 6276ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa try { 6286ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final Resources resources = 6296ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa packageManager.getResourcesForApplication(packageName); 6306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa params.directoryType = resources.getString(resourceId); 6316ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (params.directoryType == null) { 6326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Log.e(TAG, "Cannot resolve directory name: " 6336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa + resourceId + "@" + packageName); 6346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } catch (NameNotFoundException e) { 6366ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa Log.e(TAG, "Cannot resolve directory name: " 6376ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa + resourceId + "@" + packageName, e); 6386ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6406ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6416ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // If an account has been provided and we found a directory that 6426ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // corresponds to that account, place that directory second, directly 6436ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // underneath the local contacts. 64416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (account != null && account.name.equals(params.accountName) && 64516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp account.type.equals(params.accountType)) { 6466ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa preferredDirectory = params; 6476ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } else { 64874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa paramsList.add(params); 6496ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6506ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6516ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6526ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa if (preferredDirectory != null) { 65374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa paramsList.add(1, preferredDirectory); 6546ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6556ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 65674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa return paramsList; 6576ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 6586ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 6596ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 6608383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * Starts search in other directories using {@link Filter}. Results will be handled in 6618383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * {@link DirectoryFilter}. 6626ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 66376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert protected void startSearchOtherDirectories( 66474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa CharSequence constraint, List<DirectorySearchParams> paramsList, int limit) { 66574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final int count = paramsList.size(); 6666ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa // Note: skipping the default partition (index 0), which has already been loaded 6676ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa for (int i = 1; i < count; i++) { 66874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final DirectorySearchParams params = paramsList.get(i); 66974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.constraint = constraint; 67074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (params.filter == null) { 67174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.filter = new DirectoryFilter(params); 67274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 67374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.filter.setLimit(limit); 67474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa params.filter.filter(constraint); 67574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 6764bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa 6778383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // Directory search started. We may show "waiting" message if directory results are slow 6788383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // enough. 6794bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa mRemainingDirectoryCount = count - 1; 6804bb6a342f5aa1f38b0e0083d014e538e937eccceDaisuke Miyakawa mDelayedMessageHandler.sendDelayedLoadMessage(); 68174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 68274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 683f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy private static void putOneEntry(TemporaryEntry entry, boolean isAggregatedEntry, 6848383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa LinkedHashMap<Long, List<RecipientEntry>> entryMap, 6858383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa List<RecipientEntry> nonAggregatedEntries, 6868383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Set<String> existingDestinations) { 6878383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (existingDestinations.contains(entry.destination)) { 6888383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa return; 6898383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 69074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 6918383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa existingDestinations.add(entry.destination); 6928383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 6938383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (!isAggregatedEntry) { 6948383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa nonAggregatedEntries.add(RecipientEntry.constructTopLevelEntry( 6957211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.displayName, 69600adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki entry.displayNameSource, 6977211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.destination, entry.destinationType, entry.destinationLabel, 698514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy entry.contactId, entry.dataId, entry.thumbnailUriString, true, 699514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy entry.isGalContact)); 7008383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } else if (entryMap.containsKey(entry.contactId)) { 7018383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa // We already have a section for the person. 7028383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final List<RecipientEntry> entryList = entryMap.get(entry.contactId); 7038383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entryList.add(RecipientEntry.constructSecondLevelEntry( 7047211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.displayName, 70500adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki entry.displayNameSource, 7067211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.destination, entry.destinationType, entry.destinationLabel, 707514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy entry.contactId, entry.dataId, entry.thumbnailUriString, true, 708514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy entry.isGalContact)); 7098383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } else { 7108383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final List<RecipientEntry> entryList = new ArrayList<RecipientEntry>(); 7118383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entryList.add(RecipientEntry.constructTopLevelEntry( 7127211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.displayName, 71300adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki entry.displayNameSource, 7147211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa entry.destination, entry.destinationType, entry.destinationLabel, 715514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy entry.contactId, entry.dataId, entry.thumbnailUriString, true, 716514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy entry.isGalContact)); 7178383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entryMap.put(entry.contactId, entryList); 7186ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 7196ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 7206ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 7216ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa /** 72274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * Constructs an actual list for this Adapter using {@link #mEntryMap}. Also tries to 72374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa * fetch a cached photo for each contact entry (other than separators), or request another 7248383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa * thread to get one from directories. 7256ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa */ 7268383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private List<RecipientEntry> constructEntryList( 7278383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa LinkedHashMap<Long, List<RecipientEntry>> entryMap, 728f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy List<RecipientEntry> nonAggregatedEntries) { 7298383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final List<RecipientEntry> entries = new ArrayList<RecipientEntry>(); 73074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa int validEntryCount = 0; 7318383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa for (Map.Entry<Long, List<RecipientEntry>> mapEntry : entryMap.entrySet()) { 732f621a601e1f966c89b7aadbcca384021e14d668dMindy Pereira final List<RecipientEntry> entryList = mapEntry.getValue(); 7336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa final int size = entryList.size(); 7346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa for (int i = 0; i < size; i++) { 735f621a601e1f966c89b7aadbcca384021e14d668dMindy Pereira RecipientEntry entry = entryList.get(i); 7368383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entries.add(entry); 73774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa tryFetchPhoto(entry); 73874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa validEntryCount++; 7396ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 74074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (validEntryCount > mPreferredMaxResultCount) { 74174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa break; 74274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 7436ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 74474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (validEntryCount <= mPreferredMaxResultCount) { 7458383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa for (RecipientEntry entry : nonAggregatedEntries) { 74674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (validEntryCount > mPreferredMaxResultCount) { 74774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa break; 74874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 7498383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa entries.add(entry); 75074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa tryFetchPhoto(entry); 75174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 75274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa validEntryCount++; 75374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 75474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 75574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 7568383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa return entries; 7578383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 7588383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa 7598c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp 7608c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp protected interface EntriesUpdatedObserver { 7618c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp public void onChanged(List<RecipientEntry> entries); 7628c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp } 7638c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp 7648c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp public void registerUpdateObserver(EntriesUpdatedObserver observer) { 7658c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp mEntriesUpdatedObserver = observer; 7668c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp } 7678c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp 7688383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa /** Resets {@link #mEntries} and notify the event to its parent ListView. */ 7698383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa private void updateEntries(List<RecipientEntry> newEntries) { 7708383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mEntries = newEntries; 7718c474ec629cca3cf4bf2c867f37513ae35e3ff72mindyp mEntriesUpdatedObserver.onChanged(newEntries); 7726ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa notifyDataSetChanged(); 7736ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 7746ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 77537726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook private void cacheCurrentEntries() { 77637726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook mTempEntries = mEntries; 77737726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook } 77837726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 77937726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook private void clearTempEntries() { 78037726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook mTempEntries = null; 78137726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook } 78237726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 78376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert protected List<RecipientEntry> getEntries() { 78437726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook return mTempEntries != null ? mTempEntries : mEntries; 78537726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook } 78637726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook 787f621a601e1f966c89b7aadbcca384021e14d668dMindy Pereira private void tryFetchPhoto(final RecipientEntry entry) { 78874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final Uri photoThumbnailUri = entry.getPhotoThumbnailUri(); 78974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (photoThumbnailUri != null) { 79074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final byte[] photoBytes = mPhotoCacheMap.get(photoThumbnailUri); 79174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (photoBytes != null) { 79274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa entry.setPhotoBytes(photoBytes); 79374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa // notifyDataSetChanged() should be called by a caller. 79474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } else { 79574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (DEBUG) { 79674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa Log.d(TAG, "No photo cache for " + entry.getDisplayName() 79774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa + ". Fetch one asynchronously"); 7986ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 79974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa fetchPhotoAsync(entry, photoThumbnailUri); 8006ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 8016ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 8026ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 8036ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 804c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner // For reading photos for directory contacts, this is the chunksize for 805c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner // copying from the inputstream to the output stream. 806c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner private static final int BUFFER_SIZE = 1024*16; 807c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner 808f621a601e1f966c89b7aadbcca384021e14d668dMindy Pereira private void fetchPhotoAsync(final RecipientEntry entry, final Uri photoThumbnailUri) { 809c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner final AsyncTask<Void, Void, byte[]> photoLoadTask = new AsyncTask<Void, Void, byte[]>() { 81074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa @Override 811c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner protected byte[] doInBackground(Void... params) { 812c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner // First try running a query. Images for local contacts are 813c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner // loaded by sending a query to the ContactsProvider. 81474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa final Cursor photoCursor = mContentResolver.query( 81574a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa photoThumbnailUri, PhotoQuery.PROJECTION, null, null, null); 81674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (photoCursor != null) { 81774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa try { 81874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa if (photoCursor.moveToFirst()) { 819c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner return photoCursor.getBlob(PhotoQuery.PHOTO); 82074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 82174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } finally { 82274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa photoCursor.close(); 82374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 824c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner } else { 825c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner // If the query fails, try streaming the URI directly. 826c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner // For remote directory images, this URI resolves to the 827c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner // directory provider and the images are loaded by sending 828c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner // an openFile call to the provider. 829c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner try { 830c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner InputStream is = mContentResolver.openInputStream( 831c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner photoThumbnailUri); 832c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner if (is != null) { 833c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner byte[] buffer = new byte[BUFFER_SIZE]; 834c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner ByteArrayOutputStream baos = new ByteArrayOutputStream(); 835c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner try { 836c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner int size; 837c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner while ((size = is.read(buffer)) != -1) { 838c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner baos.write(buffer, 0, size); 839c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner } 840c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner } finally { 841c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner is.close(); 842c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner } 843c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner return baos.toByteArray(); 844c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner } 845c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner } catch (IOException ex) { 846c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner // ignore 847c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner } 84874a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 84934f5320d620877f757ed78a6e37754bbeabee5aaDaisuke Miyakawa return null; 85074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 851c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner 852c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner @Override 853c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner protected void onPostExecute(final byte[] photoBytes) { 854c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner entry.setPhotoBytes(photoBytes); 855c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner if (photoBytes != null) { 856c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner mPhotoCacheMap.put(photoThumbnailUri, photoBytes); 857c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner notifyDataSetChanged(); 858c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner } 859c88702e49917a21b9753d587800de25f87f2c5a8Jay Shrauner } 86034f5320d620877f757ed78a6e37754bbeabee5aaDaisuke Miyakawa }; 86134f5320d620877f757ed78a6e37754bbeabee5aaDaisuke Miyakawa photoLoadTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); 86274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 86374a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 8646b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira protected void fetchPhoto(final RecipientEntry entry, final Uri photoThumbnailUri) { 8656b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira byte[] photoBytes = mPhotoCacheMap.get(photoThumbnailUri); 8666b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira if (photoBytes != null) { 8676b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira entry.setPhotoBytes(photoBytes); 8686b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira return; 8696b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira } 8706b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira final Cursor photoCursor = mContentResolver.query(photoThumbnailUri, PhotoQuery.PROJECTION, 8716b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira null, null, null); 8726b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira if (photoCursor != null) { 8736b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira try { 8746b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira if (photoCursor.moveToFirst()) { 8756b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira photoBytes = photoCursor.getBlob(PhotoQuery.PHOTO); 8766b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira entry.setPhotoBytes(photoBytes); 8776b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira mPhotoCacheMap.put(photoThumbnailUri, photoBytes); 8786b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira } 8796b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira } finally { 8806b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira photoCursor.close(); 8816b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira } 8826b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira } 8836b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira } 8846b6de6266d3bede33728cf995f1fd5c59ec5a55dMindy Pereira 885d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa private Cursor doQuery(CharSequence constraint, int limit, Long directoryId) { 88680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor final Uri.Builder builder = mQuery.getContentFilterUri().buildUpon() 8878383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa .appendPath(constraint.toString()) 8888383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, 8898383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa String.valueOf(limit + ALLOWANCE_FOR_DUPLICATES)); 8908383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (directoryId != null) { 8918383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 8928383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa String.valueOf(directoryId)); 8938383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 8948383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (mAccount != null) { 8958383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa builder.appendQueryParameter(PRIMARY_ACCOUNT_NAME, mAccount.name); 8968383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa builder.appendQueryParameter(PRIMARY_ACCOUNT_TYPE, mAccount.type); 8978383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa } 8988383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final long start = System.currentTimeMillis(); 8998383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final Cursor cursor = mContentResolver.query( 90080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor builder.build(), mQuery.getProjection(), null, null, null); 9018383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa final long end = System.currentTimeMillis(); 9028383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa if (DEBUG) { 9038383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa Log.d(TAG, "Time for autocomplete (query: " + constraint 9048383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + ", directoryId: " + directoryId + ", num_of_results: " 9058383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + (cursor != null ? cursor.getCount() : "null") + "): " 9068383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa + (end - start) + " ms"); 907d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 908d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa return cursor; 909d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 910d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa 911cc20880f80a3a6f6e4aaef4547ed088d9364e741Daisuke Miyakawa // TODO: This won't be used at all. We should find better way to quit the thread.. 912cc20880f80a3a6f6e4aaef4547ed088d9364e741Daisuke Miyakawa /*public void close() { 9138383f44fc5608259474a24e398b2ee028f729db8Daisuke Miyakawa mEntries = null; 91474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa mPhotoCacheMap.evictAll(); 915cc20880f80a3a6f6e4aaef4547ed088d9364e741Daisuke Miyakawa if (!sPhotoHandlerThread.quit()) { 91674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa Log.w(TAG, "Failed to quit photo handler thread, ignoring it."); 91774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 918cc20880f80a3a6f6e4aaef4547ed088d9364e741Daisuke Miyakawa }*/ 9196ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 9206ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 9216ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public int getCount() { 92237726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook final List<RecipientEntry> entries = getEntries(); 92337726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook return entries != null ? entries.size() : 0; 9246ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 9256ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 9266ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 927858e094f1c695aefdf6a23f522c0f16d81bd79f7Scott Kennedy public RecipientEntry getItem(int position) { 92837726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook return getEntries().get(position); 9296ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 9306ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 9316ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 9326ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa public long getItemId(int position) { 9336ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa return position; 9346ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa } 9356ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 9366ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa @Override 93774a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public int getViewTypeCount() { 938f621a601e1f966c89b7aadbcca384021e14d668dMindy Pereira return RecipientEntry.ENTRY_TYPE_SIZE; 93974a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 94074a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa 94174a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa @Override 94274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public int getItemViewType(int position) { 94337726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook return getEntries().get(position).getEntryType(); 94474a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa } 9456ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 94674a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa @Override 9476d6bd68a492fbbfca50ae4793313083105e6f270Daisuke Miyakawa public boolean isEnabled(int position) { 94837726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook return getEntries().get(position).isSelectable(); 9496d6bd68a492fbbfca50ae4793313083105e6f270Daisuke Miyakawa } 9506d6bd68a492fbbfca50ae4793313083105e6f270Daisuke Miyakawa 9516d6bd68a492fbbfca50ae4793313083105e6f270Daisuke Miyakawa @Override 95274a977cbc35413866ca039d509801fe0b02e1901Daisuke Miyakawa public View getView(int position, View convertView, ViewGroup parent) { 95337726c00b6d53f7afd0c31b8f8f1805976ba722aPaul Westbrook final RecipientEntry entry = getEntries().get(position); 9546ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa 955b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return mDropdownChipLayouter.bindView(convertView, parent, entry, position, 956b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin AdapterType.BASE_RECIPIENT, mCurrentConstraint.toString()); 957d4baa3f2d02f1e52d325de3402e0999ac5ca65d2Daisuke Miyakawa } 95816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 95916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp public Account getAccount() { 96016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp return mAccount; 96116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 9626ac7d0c6f6db2f5af06f9f2c73f24760d4df7b84Daisuke Miyakawa} 963