AbstractContactAggregator.java revision 63a781313c71c966f9ca44a0cb3c13b477981f52
1b94bfa502569ce869d443353c174d02754d42a82Zheng Fu/* 2b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Copyright (C) 2015 The Android Open Source Project 3b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * 4b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Licensed under the Apache License, Version 2.0 (the "License"); 5b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * you may not use this file except in compliance with the License. 6b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * You may obtain a copy of the License at 7b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * 8b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * http://www.apache.org/licenses/LICENSE-2.0 9b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * 10b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Unless required by applicable law or agreed to in writing, software 11b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * distributed under the License is distributed on an "AS IS" BASIS, 12b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * See the License for the specific language governing permissions and 14b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * limitations under the License 15b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 16b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 17b94bfa502569ce869d443353c174d02754d42a82Zheng Fupackage com.android.providers.contacts.aggregation; 18b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 19b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.internal.annotations.VisibleForTesting; 20b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactLookupKey; 21b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper; 22b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns; 23b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.AggregatedPresenceColumns; 24b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns; 25b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns; 26b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns; 27b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType; 28b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns; 29b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 30b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; 31b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns; 32b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.Tables; 33b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsDatabaseHelper.Views; 34b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ContactsProvider2; 35b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.NameLookupBuilder; 36b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.NameNormalizer; 37b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.NameSplitter; 38b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.PhotoPriorityResolver; 39b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.ReorderingCursorWrapper; 40b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.TransactionContext; 41b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.aggregation.util.CommonNicknameCache; 42b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.aggregation.util.ContactAggregatorHelper; 43b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.aggregation.util.ContactMatcher; 44aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fuimport com.android.providers.contacts.aggregation.util.MatchScore; 45b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.android.providers.contacts.util.Clock; 46b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.google.android.collect.Maps; 47b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport com.google.common.collect.HashMultimap; 48aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fuimport com.google.common.collect.Multimap; 49b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 5063a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.database.Cursor; 5163a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.database.DatabaseUtils; 5263a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.database.sqlite.SQLiteDatabase; 5363a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.database.sqlite.SQLiteQueryBuilder; 5463a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.database.sqlite.SQLiteStatement; 5563a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.net.Uri; 5663a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.AggregationExceptions; 5763a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.CommonDataKinds.Email; 5863a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.CommonDataKinds.Identity; 5963a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.CommonDataKinds.Phone; 6063a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.CommonDataKinds.Photo; 6163a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.Contacts; 6263a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.Data; 6363a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.DisplayNameSources; 6463a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.FullNameStyle; 6563a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.PhotoFiles; 6663a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.PinnedPositions; 6763a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.RawContacts; 6863a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.provider.ContactsContract.StatusUpdates; 6963a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.text.TextUtils; 7063a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.util.EventLog; 7163a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fuimport android.util.Log; 7263a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fu 73b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport java.util.ArrayList; 74b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport java.util.Collections; 75b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport java.util.HashMap; 76b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport java.util.HashSet; 77b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport java.util.Iterator; 78b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport java.util.List; 79b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport java.util.Locale; 80b94bfa502569ce869d443353c174d02754d42a82Zheng Fuimport java.util.Set; 81b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 82b94bfa502569ce869d443353c174d02754d42a82Zheng Fu/** 83aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu * Base class of contact aggregator and profile aggregator 84b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 85aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fupublic abstract class AbstractContactAggregator { 86b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 87aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static final String TAG = "ContactAggregator"; 88b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 89aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static final boolean DEBUG_LOGGING = Log.isLoggable(TAG, Log.DEBUG); 90aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE); 91b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 92aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static final String STRUCTURED_NAME_BASED_LOOKUP_SQL = 93b94bfa502569ce869d443353c174d02754d42a82Zheng Fu NameLookupColumns.NAME_TYPE + " IN (" 94b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + NameLookupType.NAME_EXACT + "," 95b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + NameLookupType.NAME_VARIANT + "," 96b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + NameLookupType.NAME_COLLATION_KEY + ")"; 97b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 98b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 99b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 100b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * SQL statement that sets the {@link ContactsColumns#LAST_STATUS_UPDATE_ID} column 101b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * on the contact to point to the latest social status update. 102b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 103aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static final String UPDATE_LAST_STATUS_UPDATE_ID_SQL = 104b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "UPDATE " + Tables.CONTACTS + 105b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " SET " + ContactsColumns.LAST_STATUS_UPDATE_ID + "=" + 106b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "(SELECT " + DataColumns.CONCRETE_ID + 107b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Tables.STATUS_UPDATES + 108b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " JOIN " + Tables.DATA + 109b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " ON (" + StatusUpdatesColumns.DATA_ID + "=" 110b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + DataColumns.CONCRETE_ID + ")" + 111b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " JOIN " + Tables.RAW_CONTACTS + 112b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " ON (" + DataColumns.CONCRETE_RAW_CONTACT_ID + "=" 113b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContactsColumns.CONCRETE_ID + ")" + 114b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + RawContacts.CONTACT_ID + "=?" + 115b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " ORDER BY " + StatusUpdates.STATUS_TIMESTAMP + " DESC," 116b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + StatusUpdates.STATUS + 117b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " LIMIT 1)" + 118b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + ContactsColumns.CONCRETE_ID + "=?"; 119b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 120b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // From system/core/logcat/event-log-tags 121b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // aggregator [time, count] will be logged for each aggregator cycle. 122b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // For the query (as opposed to the merge), count will be negative 1233a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki static final int LOG_SYNC_CONTACTS_AGGREGATION = 2747; 124b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 125b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // If we encounter more than this many contacts with matching names, aggregate only this many 126aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static final int PRIMARY_HIT_LIMIT = 15; 127aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static final String PRIMARY_HIT_LIMIT_STRING = String.valueOf(PRIMARY_HIT_LIMIT); 128b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 129b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // If we encounter more than this many contacts with matching phone number or email, 130b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // don't attempt to aggregate - this is likely an error or a shared corporate data element. 131aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static final int SECONDARY_HIT_LIMIT = 20; 132aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static final String SECONDARY_HIT_LIMIT_STRING = String.valueOf(SECONDARY_HIT_LIMIT); 133b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 134b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // If we encounter no less than this many raw contacts in the best matching contact during 135b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // aggregation, don't attempt to aggregate - this is likely an error or a shared corporate 136b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // data element. 137b94bfa502569ce869d443353c174d02754d42a82Zheng Fu @VisibleForTesting 138b94bfa502569ce869d443353c174d02754d42a82Zheng Fu static final int AGGREGATION_CONTACT_SIZE_LIMIT = 50; 139b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 140b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // If we encounter more than this many contacts with matching name during aggregation 141b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // suggestion lookup, ignore the remaining results. 142aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static final int FIRST_LETTER_SUGGESTION_HIT_LIMIT = 100; 143aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu 144aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected final ContactsProvider2 mContactsProvider; 145aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected final ContactsDatabaseHelper mDbHelper; 146aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected PhotoPriorityResolver mPhotoPriorityResolver; 147aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected final NameSplitter mNameSplitter; 148aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected final CommonNicknameCache mCommonNicknameCache; 149aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu 150aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected boolean mEnabled = true; 151aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu 152aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu /** 153aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu * Precompiled sql statement for setting an aggregated presence 154aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu */ 155aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mRawContactCountQuery; 156aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mAggregatedPresenceDelete; 157aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mAggregatedPresenceReplace; 158aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mPresenceContactIdUpdate; 159aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mMarkForAggregation; 160aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mPhotoIdUpdate; 161aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mDisplayNameUpdate; 162aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mLookupKeyUpdate; 163aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mStarredUpdate; 164aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mPinnedUpdate; 165aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mContactIdAndMarkAggregatedUpdate; 166aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mContactIdUpdate; 167aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mContactUpdate; 168aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mContactInsert; 169aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected SQLiteStatement mResetPinnedForRawContact; 170aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu 171aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected HashMap<Long, Integer> mRawContactsMarkedForAggregation = Maps.newHashMap(); 172aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu 173aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected String[] mSelectionArgs1 = new String[1]; 174aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected String[] mSelectionArgs2 = new String[2]; 175aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu 176aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected long mMimeTypeIdIdentity; 177aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected long mMimeTypeIdEmail; 178aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected long mMimeTypeIdPhoto; 179aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected long mMimeTypeIdPhone; 180aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected String mRawContactsQueryByRawContactId; 181aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected String mRawContactsQueryByContactId; 182aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected StringBuilder mSb = new StringBuilder(); 183aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected MatchCandidateList mCandidates = new MatchCandidateList(); 184aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected DisplayNameCandidate mDisplayNameCandidate = new DisplayNameCandidate(); 185b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 186b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 187b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Parameter for the suggestion lookup query. 188b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 189b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final class AggregationSuggestionParameter { 190b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public final String kind; 191b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public final String value; 192b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 193b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public AggregationSuggestionParameter(String kind, String value) { 194b94bfa502569ce869d443353c174d02754d42a82Zheng Fu this.kind = kind; 195b94bfa502569ce869d443353c174d02754d42a82Zheng Fu this.value = value; 196b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 197b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 198b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 199b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 200b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Captures a potential match for a given name. The matching algorithm 201b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * constructs a bunch of NameMatchCandidate objects for various potential matches 202b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * and then executes the search in bulk. 203b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 204aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static class NameMatchCandidate { 205b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String mName; 206b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int mLookupType; 207b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 208b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public NameMatchCandidate(String name, int nameLookupType) { 209b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mName = name; 210b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mLookupType = nameLookupType; 211b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 212b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 213b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 214b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 215b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * A list of {@link NameMatchCandidate} that keeps its elements even when the list is 216b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * truncated. This is done for optimization purposes to avoid excessive object allocation. 217b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 218aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static class MatchCandidateList { 219aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected final ArrayList<NameMatchCandidate> mList = new ArrayList<NameMatchCandidate>(); 220aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected int mCount; 221b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 222b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 223b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Adds a {@link NameMatchCandidate} element or updates the next one if it already exists. 224b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 225b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public void add(String name, int nameLookupType) { 226b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (mCount >= mList.size()) { 227b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mList.add(new NameMatchCandidate(name, nameLookupType)); 228b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else { 229b94bfa502569ce869d443353c174d02754d42a82Zheng Fu NameMatchCandidate candidate = mList.get(mCount); 230b94bfa502569ce869d443353c174d02754d42a82Zheng Fu candidate.mName = name; 231b94bfa502569ce869d443353c174d02754d42a82Zheng Fu candidate.mLookupType = nameLookupType; 232b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 233b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mCount++; 234b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 235b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 236b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public void clear() { 237b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mCount = 0; 238b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 239b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 240b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public boolean isEmpty() { 241b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return mCount == 0; 242b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 243b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 244b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 245b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 246b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * A convenience class used in the algorithm that figures out which of available 247b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * display names to use for an aggregate contact. 248b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 249b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private static class DisplayNameCandidate { 250b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long rawContactId; 251b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String displayName; 252b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int displayNameSource; 253b94bfa502569ce869d443353c174d02754d42a82Zheng Fu boolean isNameSuperPrimary; 254b94bfa502569ce869d443353c174d02754d42a82Zheng Fu boolean writableAccount; 255b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 256b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public DisplayNameCandidate() { 257b94bfa502569ce869d443353c174d02754d42a82Zheng Fu clear(); 258b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 259b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 260b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public void clear() { 261b94bfa502569ce869d443353c174d02754d42a82Zheng Fu rawContactId = -1; 262b94bfa502569ce869d443353c174d02754d42a82Zheng Fu displayName = null; 263b94bfa502569ce869d443353c174d02754d42a82Zheng Fu displayNameSource = DisplayNameSources.UNDEFINED; 264b94bfa502569ce869d443353c174d02754d42a82Zheng Fu isNameSuperPrimary = false; 265b94bfa502569ce869d443353c174d02754d42a82Zheng Fu writableAccount = false; 266b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 267b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 268b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 269b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 270b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Constructor. 271b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 272aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu public AbstractContactAggregator(ContactsProvider2 contactsProvider, 273b94bfa502569ce869d443353c174d02754d42a82Zheng Fu ContactsDatabaseHelper contactsDatabaseHelper, 274b94bfa502569ce869d443353c174d02754d42a82Zheng Fu PhotoPriorityResolver photoPriorityResolver, NameSplitter nameSplitter, 275b94bfa502569ce869d443353c174d02754d42a82Zheng Fu CommonNicknameCache commonNicknameCache) { 276b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactsProvider = contactsProvider; 277b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDbHelper = contactsDatabaseHelper; 278b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPhotoPriorityResolver = photoPriorityResolver; 279b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mNameSplitter = nameSplitter; 280b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mCommonNicknameCache = commonNicknameCache; 281b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 282b94bfa502569ce869d443353c174d02754d42a82Zheng Fu SQLiteDatabase db = mDbHelper.getReadableDatabase(); 283b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 284b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Since we have no way of determining which custom status was set last, 285b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // we'll just pick one randomly. We are using MAX as an approximation of randomness 286b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final String replaceAggregatePresenceSql = 287b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "INSERT OR REPLACE INTO " + Tables.AGGREGATED_PRESENCE + "(" 288b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + AggregatedPresenceColumns.CONTACT_ID + ", " 289b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + StatusUpdates.PRESENCE + ", " 290b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + StatusUpdates.CHAT_CAPABILITY + ")" 291b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " SELECT " + PresenceColumns.CONTACT_ID + "," 292b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + StatusUpdates.PRESENCE + "," 293b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + StatusUpdates.CHAT_CAPABILITY 294b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " FROM " + Tables.PRESENCE 295b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " WHERE " 296b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " (" + StatusUpdates.PRESENCE 297b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " * 10 + " + StatusUpdates.CHAT_CAPABILITY + ")" 298b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " = (SELECT " 299b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + "MAX (" + StatusUpdates.PRESENCE 300b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " * 10 + " + StatusUpdates.CHAT_CAPABILITY + ")" 301b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " FROM " + Tables.PRESENCE 302b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " WHERE " + PresenceColumns.CONTACT_ID 303b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + "=?)" 304b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + PresenceColumns.CONTACT_ID 305b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + "=?;"; 306b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mAggregatedPresenceReplace = db.compileStatement(replaceAggregatePresenceSql); 307b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 308b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mRawContactCountQuery = db.compileStatement( 309b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "SELECT COUNT(" + RawContacts._ID + ")" + 310b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Tables.RAW_CONTACTS + 311b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + RawContacts.CONTACT_ID + "=?" 312b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + RawContacts._ID + "<>?"); 313b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 314b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mAggregatedPresenceDelete = db.compileStatement( 315b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "DELETE FROM " + Tables.AGGREGATED_PRESENCE + 316b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + AggregatedPresenceColumns.CONTACT_ID + "=?"); 317b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 318b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mMarkForAggregation = db.compileStatement( 319b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "UPDATE " + Tables.RAW_CONTACTS + 320b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " SET " + RawContactsColumns.AGGREGATION_NEEDED + "=1" + 321b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + RawContacts._ID + "=?" 322b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + RawContactsColumns.AGGREGATION_NEEDED + "=0"); 323b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 324b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPhotoIdUpdate = db.compileStatement( 325b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "UPDATE " + Tables.CONTACTS + 326b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " SET " + Contacts.PHOTO_ID + "=?," + Contacts.PHOTO_FILE_ID + "=? " + 327b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + Contacts._ID + "=?"); 328b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 329b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameUpdate = db.compileStatement( 330b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "UPDATE " + Tables.CONTACTS + 331b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " SET " + Contacts.NAME_RAW_CONTACT_ID + "=? " + 332b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + Contacts._ID + "=?"); 333b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 334b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mLookupKeyUpdate = db.compileStatement( 335b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "UPDATE " + Tables.CONTACTS + 336b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " SET " + Contacts.LOOKUP_KEY + "=? " + 337b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + Contacts._ID + "=?"); 338b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 339b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mStarredUpdate = db.compileStatement("UPDATE " + Tables.CONTACTS + " SET " 340b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.STARRED + "=(SELECT (CASE WHEN COUNT(" + RawContacts.STARRED 341b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + ")=0 THEN 0 ELSE 1 END) FROM " + Tables.RAW_CONTACTS + " WHERE " 342b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts.CONTACT_ID + "=" + ContactsColumns.CONCRETE_ID + " AND " 343b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts.STARRED + "=1)" + " WHERE " + Contacts._ID + "=?"); 344b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 345b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPinnedUpdate = db.compileStatement("UPDATE " + Tables.CONTACTS + " SET " 346b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.PINNED + " = IFNULL((SELECT MIN(" + RawContacts.PINNED + ") FROM " 347b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Tables.RAW_CONTACTS + " WHERE " + RawContacts.CONTACT_ID + "=" 348b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + ContactsColumns.CONCRETE_ID + " AND " + RawContacts.PINNED + ">" 349b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + PinnedPositions.UNPINNED + ")," + PinnedPositions.UNPINNED + ") " 350b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + "WHERE " + Contacts._ID + "=?"); 351b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 352b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactIdAndMarkAggregatedUpdate = db.compileStatement( 353b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "UPDATE " + Tables.RAW_CONTACTS + 354b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " SET " + RawContacts.CONTACT_ID + "=?, " 355b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContactsColumns.AGGREGATION_NEEDED + "=0" + 356b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + RawContacts._ID + "=?"); 357b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 358b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactIdUpdate = db.compileStatement( 359b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "UPDATE " + Tables.RAW_CONTACTS + 360b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " SET " + RawContacts.CONTACT_ID + "=?" + 361b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + RawContacts._ID + "=?"); 362b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 363b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPresenceContactIdUpdate = db.compileStatement( 364b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "UPDATE " + Tables.PRESENCE + 365b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " SET " + PresenceColumns.CONTACT_ID + "=?" + 366b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + PresenceColumns.RAW_CONTACT_ID + "=?"); 367b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 368b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactUpdate = db.compileStatement(ContactReplaceSqlStatement.UPDATE_SQL); 369b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactInsert = db.compileStatement(ContactReplaceSqlStatement.INSERT_SQL); 370b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 371b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mResetPinnedForRawContact = db.compileStatement( 372b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "UPDATE " + Tables.RAW_CONTACTS + 373b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " SET " + RawContacts.PINNED + "=" + PinnedPositions.UNPINNED + 374b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + RawContacts._ID + "=?"); 375b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 376b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mMimeTypeIdEmail = mDbHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE); 377b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mMimeTypeIdIdentity = mDbHelper.getMimeTypeId(Identity.CONTENT_ITEM_TYPE); 378b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mMimeTypeIdPhoto = mDbHelper.getMimeTypeId(Photo.CONTENT_ITEM_TYPE); 379b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mMimeTypeIdPhone = mDbHelper.getMimeTypeId(Phone.CONTENT_ITEM_TYPE); 380b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 381b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Query used to retrieve data from raw contacts to populate the corresponding aggregate 382b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mRawContactsQueryByRawContactId = String.format(Locale.US, 383b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactsQuery.SQL_FORMAT_BY_RAW_CONTACT_ID, 384b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDbHelper.getMimeTypeIdForStructuredName(), mMimeTypeIdPhoto, mMimeTypeIdPhone); 385b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 386b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mRawContactsQueryByContactId = String.format(Locale.US, 387b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactsQuery.SQL_FORMAT_BY_CONTACT_ID, 388b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDbHelper.getMimeTypeIdForStructuredName(), mMimeTypeIdPhoto, mMimeTypeIdPhone); 389b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 390b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 3913a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void setEnabled(boolean enabled) { 392b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mEnabled = enabled; 393b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 394b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 3953a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final boolean isEnabled() { 396b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return mEnabled; 397b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 398b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 399aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected interface AggregationQuery { 400b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String SQL = 401b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "SELECT " + RawContacts._ID + "," + RawContacts.CONTACT_ID + 402b94bfa502569ce869d443353c174d02754d42a82Zheng Fu ", " + RawContactsColumns.ACCOUNT_ID + 403b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Tables.RAW_CONTACTS + 404b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + RawContacts._ID + " IN("; 405b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 406b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int _ID = 0; 407b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int CONTACT_ID = 1; 408b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int ACCOUNT_ID = 2; 409b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 410b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 411b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 412b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Aggregate all raw contacts that were marked for aggregation in the current transaction. 413b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Call just before committing the transaction. 414b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 4153a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki // Overridden by ProfileAggregator. 416b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public void aggregateInTransaction(TransactionContext txContext, SQLiteDatabase db) { 417b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final int markedCount = mRawContactsMarkedForAggregation.size(); 418b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (markedCount == 0) { 419b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 420b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 421b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 422b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final long start = System.currentTimeMillis(); 423b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (DEBUG_LOGGING) { 424b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Log.d(TAG, "aggregateInTransaction for " + markedCount + " contacts"); 425b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 426b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 427b94bfa502569ce869d443353c174d02754d42a82Zheng Fu EventLog.writeEvent(LOG_SYNC_CONTACTS_AGGREGATION, start, -markedCount); 428b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 429b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int index = 0; 430b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 431b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // We don't use the cached string builder (namely mSb) here, as this string can be very 432b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // long when upgrading (where we re-aggregate all visible contacts) and StringBuilder won't 433b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // shrink the internal storage. 434b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Note: don't use selection args here. We just include all IDs directly in the selection, 435b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // because there's a limit for the number of parameters in a query. 436b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final StringBuilder sbQuery = new StringBuilder(); 437b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sbQuery.append(AggregationQuery.SQL); 438b94bfa502569ce869d443353c174d02754d42a82Zheng Fu for (long rawContactId : mRawContactsMarkedForAggregation.keySet()) { 439b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (index > 0) { 440b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sbQuery.append(','); 441b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 442b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sbQuery.append(rawContactId); 443b94bfa502569ce869d443353c174d02754d42a82Zheng Fu index++; 444b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 445b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 446b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sbQuery.append(')'); 447b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 448b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final long[] rawContactIds; 449b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final long[] contactIds; 450b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final long[] accountIds; 451b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final int actualCount; 452b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final Cursor c = db.rawQuery(sbQuery.toString(), null); 453b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 454b94bfa502569ce869d443353c174d02754d42a82Zheng Fu actualCount = c.getCount(); 455b94bfa502569ce869d443353c174d02754d42a82Zheng Fu rawContactIds = new long[actualCount]; 456b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactIds = new long[actualCount]; 457b94bfa502569ce869d443353c174d02754d42a82Zheng Fu accountIds = new long[actualCount]; 458b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 459b94bfa502569ce869d443353c174d02754d42a82Zheng Fu index = 0; 460b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (c.moveToNext()) { 461b94bfa502569ce869d443353c174d02754d42a82Zheng Fu rawContactIds[index] = c.getLong(AggregationQuery._ID); 462b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactIds[index] = c.getLong(AggregationQuery.CONTACT_ID); 463b94bfa502569ce869d443353c174d02754d42a82Zheng Fu accountIds[index] = c.getLong(AggregationQuery.ACCOUNT_ID); 464b94bfa502569ce869d443353c174d02754d42a82Zheng Fu index++; 465b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 466b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 467b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.close(); 468b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 469b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 470b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (DEBUG_LOGGING) { 471b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Log.d(TAG, "aggregateInTransaction: initial query done."); 472b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 473b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 474b94bfa502569ce869d443353c174d02754d42a82Zheng Fu for (int i = 0; i < actualCount; i++) { 475b94bfa502569ce869d443353c174d02754d42a82Zheng Fu aggregateContact(txContext, db, rawContactIds[i], accountIds[i], contactIds[i], 476aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu mCandidates); 477b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 478b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 479b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long elapsedTime = System.currentTimeMillis() - start; 480b94bfa502569ce869d443353c174d02754d42a82Zheng Fu EventLog.writeEvent(LOG_SYNC_CONTACTS_AGGREGATION, elapsedTime, actualCount); 481b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 482b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (DEBUG_LOGGING) { 483b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Log.d(TAG, "Contact aggregation complete: " + actualCount + 484b94bfa502569ce869d443353c174d02754d42a82Zheng Fu (actualCount == 0 ? "" : ", " + (elapsedTime / actualCount) 485b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " ms per raw contact")); 486b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 487b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 488b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 489b94bfa502569ce869d443353c174d02754d42a82Zheng Fu @SuppressWarnings("deprecation") 4903a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void triggerAggregation(TransactionContext txContext, long rawContactId) { 491b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (!mEnabled) { 492b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 493b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 494b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 495b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int aggregationMode = mDbHelper.getAggregationMode(rawContactId); 496b94bfa502569ce869d443353c174d02754d42a82Zheng Fu switch (aggregationMode) { 497b94bfa502569ce869d443353c174d02754d42a82Zheng Fu case RawContacts.AGGREGATION_MODE_DISABLED: 498b94bfa502569ce869d443353c174d02754d42a82Zheng Fu break; 499b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 500b94bfa502569ce869d443353c174d02754d42a82Zheng Fu case RawContacts.AGGREGATION_MODE_DEFAULT: { 501b94bfa502569ce869d443353c174d02754d42a82Zheng Fu markForAggregation(rawContactId, aggregationMode, false); 502b94bfa502569ce869d443353c174d02754d42a82Zheng Fu break; 503b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 504b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 505b94bfa502569ce869d443353c174d02754d42a82Zheng Fu case RawContacts.AGGREGATION_MODE_SUSPENDED: { 506b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long contactId = mDbHelper.getContactId(rawContactId); 507b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 508b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (contactId != 0) { 509b94bfa502569ce869d443353c174d02754d42a82Zheng Fu updateAggregateData(txContext, contactId); 510b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 511b94bfa502569ce869d443353c174d02754d42a82Zheng Fu break; 512b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 513b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 514b94bfa502569ce869d443353c174d02754d42a82Zheng Fu case RawContacts.AGGREGATION_MODE_IMMEDIATE: { 515b94bfa502569ce869d443353c174d02754d42a82Zheng Fu aggregateContact(txContext, mDbHelper.getWritableDatabase(), rawContactId); 516b94bfa502569ce869d443353c174d02754d42a82Zheng Fu break; 517b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 518b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 519b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 520b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 5213a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void clearPendingAggregations() { 522b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // HashMap woulnd't shrink the internal table once expands it, so let's just re-create 523b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // a new one instead of clear()ing it. 524b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mRawContactsMarkedForAggregation = Maps.newHashMap(); 525b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 526b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 5273a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void markNewForAggregation(long rawContactId, int aggregationMode) { 528b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mRawContactsMarkedForAggregation.put(rawContactId, aggregationMode); 529b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 530b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 5313a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void markForAggregation(long rawContactId, int aggregationMode, boolean force) { 532b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final int effectiveAggregationMode; 533b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (!force && mRawContactsMarkedForAggregation.containsKey(rawContactId)) { 534b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // As per ContactsContract documentation, default aggregation mode 535b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // does not override a previously set mode 536b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (aggregationMode == RawContacts.AGGREGATION_MODE_DEFAULT) { 537b94bfa502569ce869d443353c174d02754d42a82Zheng Fu effectiveAggregationMode = mRawContactsMarkedForAggregation.get(rawContactId); 538b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else { 539b94bfa502569ce869d443353c174d02754d42a82Zheng Fu effectiveAggregationMode = aggregationMode; 540b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 541b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else { 542b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mMarkForAggregation.bindLong(1, rawContactId); 543b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mMarkForAggregation.execute(); 544b94bfa502569ce869d443353c174d02754d42a82Zheng Fu effectiveAggregationMode = aggregationMode; 545b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 546b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 547b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mRawContactsMarkedForAggregation.put(rawContactId, effectiveAggregationMode); 548b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 549b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 550b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private static class RawContactIdAndAggregationModeQuery { 551b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final String TABLE = Tables.RAW_CONTACTS; 552b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 553aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu public static final String[] COLUMNS = {RawContacts._ID, RawContacts.AGGREGATION_MODE}; 554b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 555b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final String SELECTION = RawContacts.CONTACT_ID + "=?"; 556b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 557b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final int _ID = 0; 558b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final int AGGREGATION_MODE = 1; 559b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 560b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 561b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 562b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Marks all constituent raw contacts of an aggregated contact for re-aggregation. 563b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 5643a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final void markContactForAggregation(SQLiteDatabase db, long contactId) { 565b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelectionArgs1[0] = String.valueOf(contactId); 566b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Cursor cursor = db.query(RawContactIdAndAggregationModeQuery.TABLE, 567b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactIdAndAggregationModeQuery.COLUMNS, 568b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactIdAndAggregationModeQuery.SELECTION, mSelectionArgs1, null, null, null); 569b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 570b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (cursor.moveToFirst()) { 571b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long rawContactId = cursor.getLong(RawContactIdAndAggregationModeQuery._ID); 572b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int aggregationMode = cursor.getInt( 573b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactIdAndAggregationModeQuery.AGGREGATION_MODE); 574b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Don't re-aggregate AGGREGATION_MODE_SUSPENDED / AGGREGATION_MODE_DISABLED. 575b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // (Also just ignore deprecated AGGREGATION_MODE_IMMEDIATE) 576b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (aggregationMode == RawContacts.AGGREGATION_MODE_DEFAULT) { 577b94bfa502569ce869d443353c174d02754d42a82Zheng Fu markForAggregation(rawContactId, aggregationMode, true); 578b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 579b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 580b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 581b94bfa502569ce869d443353c174d02754d42a82Zheng Fu cursor.close(); 582b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 583b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 584b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 585b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 586b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Mark all visible contacts for re-aggregation. 587b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * 588b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * - Set {@link RawContactsColumns#AGGREGATION_NEEDED} For all visible raw_contacts with 589b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * {@link RawContacts#AGGREGATION_MODE_DEFAULT}. 590b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * - Also put them into {@link #mRawContactsMarkedForAggregation}. 591b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 5923a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final int markAllVisibleForAggregation(SQLiteDatabase db) { 593b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final long start = System.currentTimeMillis(); 594b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 595b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Set AGGREGATION_NEEDED for all visible raw_cotnacts with AGGREGATION_MODE_DEFAULT. 596b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // (Don't re-aggregate AGGREGATION_MODE_SUSPENDED / AGGREGATION_MODE_DISABLED) 597b94bfa502569ce869d443353c174d02754d42a82Zheng Fu db.execSQL("UPDATE " + Tables.RAW_CONTACTS + " SET " + 598b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactsColumns.AGGREGATION_NEEDED + "=1" + 599b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + RawContacts.CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY + 600b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND " + RawContacts.AGGREGATION_MODE + "=" + RawContacts.AGGREGATION_MODE_DEFAULT 601b94bfa502569ce869d443353c174d02754d42a82Zheng Fu ); 602b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 603b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final int count; 604b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final Cursor cursor = db.rawQuery("SELECT " + RawContacts._ID + 605b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Tables.RAW_CONTACTS + 606cc9ce6b1c8f9d7c4d8b4da96003ce74ccaa636ccZheng Fu " WHERE " + RawContactsColumns.AGGREGATION_NEEDED + "=1 AND " + 607cc9ce6b1c8f9d7c4d8b4da96003ce74ccaa636ccZheng Fu RawContacts.DELETED + "=0", null); 608b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 609b94bfa502569ce869d443353c174d02754d42a82Zheng Fu count = cursor.getCount(); 610b94bfa502569ce869d443353c174d02754d42a82Zheng Fu cursor.moveToPosition(-1); 611b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (cursor.moveToNext()) { 612b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final long rawContactId = cursor.getLong(0); 613b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mRawContactsMarkedForAggregation.put(rawContactId, 614b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContacts.AGGREGATION_MODE_DEFAULT); 615b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 616b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 617b94bfa502569ce869d443353c174d02754d42a82Zheng Fu cursor.close(); 618b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 619b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 620b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final long end = System.currentTimeMillis(); 621b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Log.i(TAG, "Marked all visible contacts for aggregation: " + count + " raw contacts, " + 622b94bfa502569ce869d443353c174d02754d42a82Zheng Fu (end - start) + " ms"); 623b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return count; 624b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 625b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 626b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 627b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Creates a new contact based on the given raw contact. Does not perform aggregation. Returns 628b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * the ID of the contact that was created. 629b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 6303a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki // Overridden by ProfileAggregator. 631b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public long onRawContactInsert( 632b94bfa502569ce869d443353c174d02754d42a82Zheng Fu TransactionContext txContext, SQLiteDatabase db, long rawContactId) { 633b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long contactId = insertContact(db, rawContactId); 634b94bfa502569ce869d443353c174d02754d42a82Zheng Fu setContactId(rawContactId, contactId); 635b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDbHelper.updateContactVisible(txContext, contactId); 636b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return contactId; 637b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 638b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 6393a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final long insertContact(SQLiteDatabase db, long rawContactId) { 640b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelectionArgs1[0] = String.valueOf(rawContactId); 641b94bfa502569ce869d443353c174d02754d42a82Zheng Fu computeAggregateData(db, mRawContactsQueryByRawContactId, mSelectionArgs1, mContactInsert); 642b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return mContactInsert.executeInsert(); 643b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 644b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 645b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private static final class RawContactIdAndAccountQuery { 646b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final String TABLE = Tables.RAW_CONTACTS; 647b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 648b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final String[] COLUMNS = { 649b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContacts.CONTACT_ID, 650b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactsColumns.ACCOUNT_ID 651b94bfa502569ce869d443353c174d02754d42a82Zheng Fu }; 652b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 653b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final String SELECTION = RawContacts._ID + "=?"; 654b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 655b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final int CONTACT_ID = 0; 656b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final int ACCOUNT_ID = 1; 657b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 658b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 6593a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki // Overridden by ProfileAggregator. 660b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public void aggregateContact( 661b94bfa502569ce869d443353c174d02754d42a82Zheng Fu TransactionContext txContext, SQLiteDatabase db, long rawContactId) { 662b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (!mEnabled) { 663b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 664b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 665b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 666b94bfa502569ce869d443353c174d02754d42a82Zheng Fu MatchCandidateList candidates = new MatchCandidateList(); 667b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 668b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long contactId = 0; 669b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long accountId = 0; 670b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelectionArgs1[0] = String.valueOf(rawContactId); 671b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Cursor cursor = db.query(RawContactIdAndAccountQuery.TABLE, 672b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactIdAndAccountQuery.COLUMNS, RawContactIdAndAccountQuery.SELECTION, 673b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelectionArgs1, null, null, null); 674b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 675b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (cursor.moveToFirst()) { 676b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactId = cursor.getLong(RawContactIdAndAccountQuery.CONTACT_ID); 677b94bfa502569ce869d443353c174d02754d42a82Zheng Fu accountId = cursor.getLong(RawContactIdAndAccountQuery.ACCOUNT_ID); 678b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 679b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 680b94bfa502569ce869d443353c174d02754d42a82Zheng Fu cursor.close(); 681b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 682b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 683b94bfa502569ce869d443353c174d02754d42a82Zheng Fu aggregateContact(txContext, db, rawContactId, accountId, contactId, 684aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu candidates); 685b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 686b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 687b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public void updateAggregateData(TransactionContext txContext, long contactId) { 688b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (!mEnabled) { 689b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 690b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 691b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 692b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final SQLiteDatabase db = mDbHelper.getWritableDatabase(); 693b94bfa502569ce869d443353c174d02754d42a82Zheng Fu computeAggregateData(db, contactId, mContactUpdate); 694b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactUpdate.bindLong(ContactReplaceSqlStatement.CONTACT_ID, contactId); 695b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactUpdate.execute(); 696b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 697b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDbHelper.updateContactVisible(txContext, contactId); 698b94bfa502569ce869d443353c174d02754d42a82Zheng Fu updateAggregatedStatusUpdate(contactId); 699b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 700b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 7013a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final void updateAggregatedStatusUpdate(long contactId) { 702b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mAggregatedPresenceReplace.bindLong(1, contactId); 703b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mAggregatedPresenceReplace.bindLong(2, contactId); 704b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mAggregatedPresenceReplace.execute(); 705b94bfa502569ce869d443353c174d02754d42a82Zheng Fu updateLastStatusUpdateId(contactId); 706b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 707b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 708b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 709b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Adjusts the reference to the latest status update for the specified contact. 710b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 7113a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void updateLastStatusUpdateId(long contactId) { 712b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String contactIdString = String.valueOf(contactId); 713b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDbHelper.getWritableDatabase().execSQL(UPDATE_LAST_STATUS_UPDATE_ID_SQL, 714b94bfa502569ce869d443353c174d02754d42a82Zheng Fu new String[]{contactIdString, contactIdString}); 715b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 716b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 717b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 718b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Given a specific raw contact, finds all matching aggregate contacts and chooses the one 719b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * with the highest match score. If no such contact is found, creates a new contact. 720b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 721aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu abstract void aggregateContact(TransactionContext txContext, SQLiteDatabase db, 722aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu long rawContactId, long accountId, long currentContactId, 723aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu MatchCandidateList candidates); 724b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 725b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 726aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected interface RawContactMatchingSelectionStatement { 727aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu String SELECT_COUNT = "SELECT count(*) "; 728aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu String SELECT_ID = "SELECT d1." + Data.RAW_CONTACT_ID + ",d2." + Data.RAW_CONTACT_ID; 729b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 730b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 731b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 732b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Build sql to check if there is any identity match/mis-match between two sets of raw contact 733b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * ids on the same namespace. 734b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 7353a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final String buildIdentityMatchingSql(String rawContactIdSet1, 7363a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki String rawContactIdSet2, boolean isIdentityMatching, boolean countOnly) { 737b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final String identityType = String.valueOf(mMimeTypeIdIdentity); 738b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final String matchingOperator = (isIdentityMatching) ? "=" : "!="; 739b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final String sql = 740b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Tables.DATA + " AS d1" + 741b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " JOIN " + Tables.DATA + " AS d2" + 742b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " ON (d1." + Identity.IDENTITY + matchingOperator + 743b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " d2." + Identity.IDENTITY + " AND" + 744b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " d1." + Identity.NAMESPACE + " = d2." + Identity.NAMESPACE + " )" + 745b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE d1." + DataColumns.MIMETYPE_ID + " = " + identityType + 746b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d2." + DataColumns.MIMETYPE_ID + " = " + identityType + 747b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d1." + Data.RAW_CONTACT_ID + " IN (" + rawContactIdSet1 + ")" + 748b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d2." + Data.RAW_CONTACT_ID + " IN (" + rawContactIdSet2 + ")"; 749b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return (countOnly) ? RawContactMatchingSelectionStatement.SELECT_COUNT + sql : 750b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactMatchingSelectionStatement.SELECT_ID + sql; 751b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 752b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 7533a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final String buildEmailMatchingSql(String rawContactIdSet1, String rawContactIdSet2, 754b94bfa502569ce869d443353c174d02754d42a82Zheng Fu boolean countOnly) { 755b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final String emailType = String.valueOf(mMimeTypeIdEmail); 756b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final String sql = 757b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Tables.DATA + " AS d1" + 758b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " JOIN " + Tables.DATA + " AS d2" + 759d0d961e19f19704f7967dadf5be61fe6273a1d32Zheng Fu " ON d1." + Email.ADDRESS + "= d2." + Email.ADDRESS + 760b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE d1." + DataColumns.MIMETYPE_ID + " = " + emailType + 761b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d2." + DataColumns.MIMETYPE_ID + " = " + emailType + 762b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d1." + Data.RAW_CONTACT_ID + " IN (" + rawContactIdSet1 + ")" + 763b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d2." + Data.RAW_CONTACT_ID + " IN (" + rawContactIdSet2 + ")"; 764b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return (countOnly) ? RawContactMatchingSelectionStatement.SELECT_COUNT + sql : 765b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactMatchingSelectionStatement.SELECT_ID + sql; 766b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 767b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 7683a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final String buildPhoneMatchingSql(String rawContactIdSet1, String rawContactIdSet2, 769b94bfa502569ce869d443353c174d02754d42a82Zheng Fu boolean countOnly) { 770b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // It's a bit tricker because it has to be consistent with 771b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // updateMatchScoresBasedOnPhoneMatches(). 772b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final String phoneType = String.valueOf(mMimeTypeIdPhone); 773b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final String sql = 774b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Tables.PHONE_LOOKUP + " AS p1" + 775b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " JOIN " + Tables.DATA + " AS d1 ON " + 776b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "(d1." + Data._ID + "=p1." + PhoneLookupColumns.DATA_ID + ")" + 777b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " JOIN " + Tables.PHONE_LOOKUP + " AS p2 ON (p1." + PhoneLookupColumns.MIN_MATCH + 778b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "=p2." + PhoneLookupColumns.MIN_MATCH + ")" + 779b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " JOIN " + Tables.DATA + " AS d2 ON " + 780b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "(d2." + Data._ID + "=p2." + PhoneLookupColumns.DATA_ID + ")" + 781b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE d1." + DataColumns.MIMETYPE_ID + " = " + phoneType + 782b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d2." + DataColumns.MIMETYPE_ID + " = " + phoneType + 783b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d1." + Data.RAW_CONTACT_ID + " IN (" + rawContactIdSet1 + ")" + 784b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d2." + Data.RAW_CONTACT_ID + " IN (" + rawContactIdSet2 + ")" + 785b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND PHONE_NUMBERS_EQUAL(d1." + Phone.NUMBER + ",d2." + Phone.NUMBER + "," + 786b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String.valueOf(mDbHelper.getUseStrictPhoneNumberComparisonParameter()) + 787b94bfa502569ce869d443353c174d02754d42a82Zheng Fu ")"; 788b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return (countOnly) ? RawContactMatchingSelectionStatement.SELECT_COUNT + sql : 789b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactMatchingSelectionStatement.SELECT_ID + sql; 790b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 791b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 7923a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final String buildExceptionMatchingSql(String rawContactIdSet1, 7933a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki String rawContactIdSet2) { 794b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return "SELECT " + AggregationExceptions.RAW_CONTACT_ID1 + ", " + 795b94bfa502569ce869d443353c174d02754d42a82Zheng Fu AggregationExceptions.RAW_CONTACT_ID2 + 796b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Tables.AGGREGATION_EXCEPTIONS + 797b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + AggregationExceptions.RAW_CONTACT_ID1 + " IN (" + 798aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu rawContactIdSet1 + ")" + 799b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND " + AggregationExceptions.RAW_CONTACT_ID2 + " IN (" + rawContactIdSet2 + ")" + 800b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND " + AggregationExceptions.TYPE + "=" + 801aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu AggregationExceptions.TYPE_KEEP_TOGETHER ; 802b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 803b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 8043a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final boolean isFirstColumnGreaterThanZero(SQLiteDatabase db, String query) { 805b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return DatabaseUtils.longForQuery(db, query, null) > 0; 806b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 807b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 808b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 809b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Partition the given raw contact Ids to connected component based on aggregation exception, 810b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * identity matching, email matching or phone matching. 811b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 8123a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final Set<Set<Long>> findConnectedRawContacts(SQLiteDatabase db, Set<Long> 813aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu rawContactIdSet) { 814b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Connections between two raw contacts 815aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu final Multimap<Long, Long> matchingRawIdPairs = HashMultimap.create(); 816b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String rawContactIds = TextUtils.join(",", rawContactIdSet); 817b94bfa502569ce869d443353c174d02754d42a82Zheng Fu findIdPairs(db, buildExceptionMatchingSql(rawContactIds, rawContactIds), 818b94bfa502569ce869d443353c174d02754d42a82Zheng Fu matchingRawIdPairs); 819b94bfa502569ce869d443353c174d02754d42a82Zheng Fu findIdPairs(db, buildIdentityMatchingSql(rawContactIds, rawContactIds, 820b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /* isIdentityMatching =*/ true, /* countOnly =*/false), matchingRawIdPairs); 821b94bfa502569ce869d443353c174d02754d42a82Zheng Fu findIdPairs(db, buildEmailMatchingSql(rawContactIds, rawContactIds, /* countOnly =*/false), 822b94bfa502569ce869d443353c174d02754d42a82Zheng Fu matchingRawIdPairs); 823b94bfa502569ce869d443353c174d02754d42a82Zheng Fu findIdPairs(db, buildPhoneMatchingSql(rawContactIds, rawContactIds, /* countOnly =*/false), 824b94bfa502569ce869d443353c174d02754d42a82Zheng Fu matchingRawIdPairs); 825b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 826b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return ContactAggregatorHelper.findConnectedComponents(rawContactIdSet, matchingRawIdPairs); 827b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 828b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 829b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 830b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Given a query which will return two non-null IDs in the first two columns as results, this 831b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * method will put two entries into the given result map for each pair of different IDs, one 832b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * keyed by each ID. 833b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 8343a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final void findIdPairs(SQLiteDatabase db, String query, 8353a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki Multimap<Long, Long> results) { 836b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Cursor cursor = db.rawQuery(query, null); 837b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 838b94bfa502569ce869d443353c174d02754d42a82Zheng Fu cursor.moveToPosition(-1); 839b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (cursor.moveToNext()) { 840b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long idA = cursor.getLong(0); 841b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long idB = cursor.getLong(1); 842b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (idA != idB) { 843b94bfa502569ce869d443353c174d02754d42a82Zheng Fu results.put(idA, idB); 844b94bfa502569ce869d443353c174d02754d42a82Zheng Fu results.put(idB, idA); 845b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 846b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 847b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 848b94bfa502569ce869d443353c174d02754d42a82Zheng Fu cursor.close(); 849b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 850b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 851b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 852b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 853b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Creates a new Contact for a given set of the raw contacts of {@code rawContactIds} if the 854b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * given contactId is null. Otherwise, regroup them into contact with {@code contactId}. 855b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 8563a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final void createContactForRawContacts(SQLiteDatabase db, 8573a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki TransactionContext txContext, Set<Long> rawContactIds, Long contactId) { 858b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (rawContactIds.isEmpty()) { 859b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // No raw contact id is provided. 860b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 861b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 862b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 863b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // If contactId is not provided, generates a new one. 864b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (contactId == null) { 865aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu mSelectionArgs1[0] = String.valueOf(rawContactIds.iterator().next()); 866b94bfa502569ce869d443353c174d02754d42a82Zheng Fu computeAggregateData(db, mRawContactsQueryByRawContactId, mSelectionArgs1, 867b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactInsert); 868b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactId = mContactInsert.executeInsert(); 869b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 870b94bfa502569ce869d443353c174d02754d42a82Zheng Fu for (Long rawContactId : rawContactIds) { 871b94bfa502569ce869d443353c174d02754d42a82Zheng Fu setContactIdAndMarkAggregated(rawContactId, contactId); 872b94bfa502569ce869d443353c174d02754d42a82Zheng Fu setPresenceContactId(rawContactId, contactId); 873b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 874b94bfa502569ce869d443353c174d02754d42a82Zheng Fu updateAggregateData(txContext, contactId); 875b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 876b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 877aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected static class RawContactIdQuery { 878b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final String TABLE = Tables.RAW_CONTACTS; 879aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu public static final String[] COLUMNS = {RawContacts._ID, RawContactsColumns.ACCOUNT_ID }; 880b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final String SELECTION = RawContacts.CONTACT_ID + "=?"; 881b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public static final int RAW_CONTACT_ID = 0; 882aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu public static final int ACCOUNT_ID = 1; 883b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 884b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 885b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 886b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Updates the contact ID for the specified contact. 887b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 8883a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final void setContactId(long rawContactId, long contactId) { 889b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactIdUpdate.bindLong(1, contactId); 890b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactIdUpdate.bindLong(2, rawContactId); 891b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactIdUpdate.execute(); 892b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 893b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 894b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 895d0d961e19f19704f7967dadf5be61fe6273a1d32Zheng Fu * Marks the list of raw contact IDs as aggregated. 896d0d961e19f19704f7967dadf5be61fe6273a1d32Zheng Fu * 897d0d961e19f19704f7967dadf5be61fe6273a1d32Zheng Fu * @param rawContactIds comma separated raw contact ids 898b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 899d0d961e19f19704f7967dadf5be61fe6273a1d32Zheng Fu protected final void markAggregated(SQLiteDatabase db, String rawContactIds) { 900d0d961e19f19704f7967dadf5be61fe6273a1d32Zheng Fu final String sql = "UPDATE " + Tables.RAW_CONTACTS + 901d0d961e19f19704f7967dadf5be61fe6273a1d32Zheng Fu " SET " + RawContactsColumns.AGGREGATION_NEEDED + "=0" + 902d0d961e19f19704f7967dadf5be61fe6273a1d32Zheng Fu " WHERE " + RawContacts._ID + " in (" + rawContactIds + ")"; 903d0d961e19f19704f7967dadf5be61fe6273a1d32Zheng Fu db.execSQL(sql); 904b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 905b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 906b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 907b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Updates the contact ID for the specified contact and marks the raw contact as aggregated. 908b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 909b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private void setContactIdAndMarkAggregated(long rawContactId, long contactId) { 910b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactIdAndMarkAggregatedUpdate.bindLong(1, contactId); 911b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactIdAndMarkAggregatedUpdate.bindLong(2, rawContactId); 912b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactIdAndMarkAggregatedUpdate.execute(); 913b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 914b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 915b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private void setPresenceContactId(long rawContactId, long contactId) { 916b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPresenceContactIdUpdate.bindLong(1, contactId); 917b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPresenceContactIdUpdate.bindLong(2, rawContactId); 918b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPresenceContactIdUpdate.execute(); 919b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 920b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 921b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private void unpinRawContact(long rawContactId) { 922b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mResetPinnedForRawContact.bindLong(1, rawContactId); 923b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mResetPinnedForRawContact.execute(); 924b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 925b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 926b94bfa502569ce869d443353c174d02754d42a82Zheng Fu interface AggregateExceptionPrefetchQuery { 927b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String TABLE = Tables.AGGREGATION_EXCEPTIONS; 928b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 929b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String[] COLUMNS = { 930aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu AggregationExceptions.RAW_CONTACT_ID1, 931aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu AggregationExceptions.RAW_CONTACT_ID2, 932b94bfa502569ce869d443353c174d02754d42a82Zheng Fu }; 933b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 934b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int RAW_CONTACT_ID1 = 0; 935b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int RAW_CONTACT_ID2 = 1; 936b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 937b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 938b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // A set of raw contact IDs for which there are aggregation exceptions 939aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected final HashSet<Long> mAggregationExceptionIds = new HashSet<Long>(); 940aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected boolean mAggregationExceptionIdsValid; 941b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 9423a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void invalidateAggregationExceptionCache() { 943b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mAggregationExceptionIdsValid = false; 944b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 945b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 946b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 947b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Finds all raw contact IDs for which there are aggregation exceptions. The list of 948b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * ids is used as an optimization in aggregation: there is no point to run a query against 949b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * the agg_exceptions table if it is known that there are no records there for a given 950b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * raw contact ID. 951b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 9523a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final void prefetchAggregationExceptionIds(SQLiteDatabase db) { 953b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mAggregationExceptionIds.clear(); 954b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final Cursor c = db.query(AggregateExceptionPrefetchQuery.TABLE, 955b94bfa502569ce869d443353c174d02754d42a82Zheng Fu AggregateExceptionPrefetchQuery.COLUMNS, 956b94bfa502569ce869d443353c174d02754d42a82Zheng Fu null, null, null, null, null); 957b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 958b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 959b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (c.moveToNext()) { 960b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long rawContactId1 = c.getLong(AggregateExceptionPrefetchQuery.RAW_CONTACT_ID1); 961b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long rawContactId2 = c.getLong(AggregateExceptionPrefetchQuery.RAW_CONTACT_ID2); 962b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mAggregationExceptionIds.add(rawContactId1); 963b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mAggregationExceptionIds.add(rawContactId2); 964b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 965b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 966b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.close(); 967b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 968b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 969b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mAggregationExceptionIdsValid = true; 970b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 971b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 972aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected interface NameLookupQuery { 973b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String TABLE = Tables.NAME_LOOKUP; 974b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 975b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String SELECTION = NameLookupColumns.RAW_CONTACT_ID + "=?"; 976b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String SELECTION_STRUCTURED_NAME_BASED = 977b94bfa502569ce869d443353c174d02754d42a82Zheng Fu SELECTION + " AND " + STRUCTURED_NAME_BASED_LOOKUP_SQL; 978b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 979b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String[] COLUMNS = new String[] { 980b94bfa502569ce869d443353c174d02754d42a82Zheng Fu NameLookupColumns.NORMALIZED_NAME, 981b94bfa502569ce869d443353c174d02754d42a82Zheng Fu NameLookupColumns.NAME_TYPE 982b94bfa502569ce869d443353c174d02754d42a82Zheng Fu }; 983b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 984b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int NORMALIZED_NAME = 0; 985b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int NAME_TYPE = 1; 986b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 987b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 9883a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final void loadNameMatchCandidates(SQLiteDatabase db, long rawContactId, 989b94bfa502569ce869d443353c174d02754d42a82Zheng Fu MatchCandidateList candidates, boolean structuredNameBased) { 990b94bfa502569ce869d443353c174d02754d42a82Zheng Fu candidates.clear(); 991b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelectionArgs1[0] = String.valueOf(rawContactId); 992b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Cursor c = db.query(NameLookupQuery.TABLE, NameLookupQuery.COLUMNS, 993b94bfa502569ce869d443353c174d02754d42a82Zheng Fu structuredNameBased 994b94bfa502569ce869d443353c174d02754d42a82Zheng Fu ? NameLookupQuery.SELECTION_STRUCTURED_NAME_BASED 995b94bfa502569ce869d443353c174d02754d42a82Zheng Fu : NameLookupQuery.SELECTION, 996b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelectionArgs1, null, null, null); 997b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 998b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (c.moveToNext()) { 999b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String normalizedName = c.getString(NameLookupQuery.NORMALIZED_NAME); 1000b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int type = c.getInt(NameLookupQuery.NAME_TYPE); 1001b94bfa502569ce869d443353c174d02754d42a82Zheng Fu candidates.add(normalizedName, type); 1002b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1003b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 1004b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.close(); 1005b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1006b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1007b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1008aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu interface AggregateExceptionQuery { 1009aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu String TABLE = Tables.AGGREGATION_EXCEPTIONS 1010aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu + " JOIN raw_contacts raw_contacts1 " 1011aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu + " ON (agg_exceptions.raw_contact_id1 = raw_contacts1._id) " 1012aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu + " JOIN raw_contacts raw_contacts2 " 1013aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu + " ON (agg_exceptions.raw_contact_id2 = raw_contacts2._id) "; 1014b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1015aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu String[] COLUMNS = { 1016aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu AggregationExceptions.TYPE, 1017aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu AggregationExceptions.RAW_CONTACT_ID1, 1018aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu "raw_contacts1." + RawContacts.CONTACT_ID, 1019aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu "raw_contacts1." + RawContactsColumns.ACCOUNT_ID, 1020aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu "raw_contacts1." + RawContactsColumns.AGGREGATION_NEEDED, 1021aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu AggregationExceptions.RAW_CONTACT_ID2, 1022aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu "raw_contacts2." + RawContacts.CONTACT_ID, 1023aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu "raw_contacts2." + RawContactsColumns.ACCOUNT_ID, 1024aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu "raw_contacts2." + RawContactsColumns.AGGREGATION_NEEDED, 1025aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu }; 1026aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu 1027aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int TYPE = 0; 1028aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int RAW_CONTACT_ID1 = 1; 1029aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int CONTACT_ID1 = 2; 1030aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int ACCOUNT_ID1 = 3; 1031aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int AGGREGATION_NEEDED_1 = 4; 1032aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int RAW_CONTACT_ID2 = 5; 1033aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int CONTACT_ID2 = 6; 1034aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int ACCOUNT_ID2 = 7; 1035aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int AGGREGATION_NEEDED_2 = 8; 1036b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1037b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1038aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected interface NameLookupMatchQueryWithParameter { 1039b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String TABLE = Tables.NAME_LOOKUP 1040b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " JOIN " + Tables.RAW_CONTACTS + 1041b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " ON (" + NameLookupColumns.RAW_CONTACT_ID + " = " 1042b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Tables.RAW_CONTACTS + "." + RawContacts._ID + ")"; 1043b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1044b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String[] COLUMNS = new String[] { 1045aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu RawContacts._ID, 1046aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu RawContacts.CONTACT_ID, 1047aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu RawContactsColumns.ACCOUNT_ID, 1048aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu NameLookupColumns.NORMALIZED_NAME, 1049aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu NameLookupColumns.NAME_TYPE, 1050b94bfa502569ce869d443353c174d02754d42a82Zheng Fu }; 1051b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1052aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int RAW_CONTACT_ID = 0; 1053aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int CONTACT_ID = 1; 1054aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int ACCOUNT_ID = 2; 1055aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int NAME = 3; 1056aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int NAME_TYPE = 4; 1057b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1058b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1059aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected final class NameLookupSelectionBuilder extends NameLookupBuilder { 1060b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1061b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private final MatchCandidateList mNameLookupCandidates; 1062b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1063b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private StringBuilder mSelection = new StringBuilder( 1064b94bfa502569ce869d443353c174d02754d42a82Zheng Fu NameLookupColumns.NORMALIZED_NAME + " IN("); 1065b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1066b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1067b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public NameLookupSelectionBuilder(NameSplitter splitter, MatchCandidateList candidates) { 1068b94bfa502569ce869d443353c174d02754d42a82Zheng Fu super(splitter); 1069b94bfa502569ce869d443353c174d02754d42a82Zheng Fu this.mNameLookupCandidates = candidates; 1070b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1071b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1072b94bfa502569ce869d443353c174d02754d42a82Zheng Fu @Override 1073b94bfa502569ce869d443353c174d02754d42a82Zheng Fu protected String[] getCommonNicknameClusters(String normalizedName) { 1074b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); 1075b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1076b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1077b94bfa502569ce869d443353c174d02754d42a82Zheng Fu @Override 1078b94bfa502569ce869d443353c174d02754d42a82Zheng Fu protected void insertNameLookup( 1079b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long rawContactId, long dataId, int lookupType, String string) { 1080b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mNameLookupCandidates.add(string, lookupType); 1081b94bfa502569ce869d443353c174d02754d42a82Zheng Fu DatabaseUtils.appendEscapedSQLString(mSelection, string); 1082b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelection.append(','); 1083b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1084b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1085b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public boolean isEmpty() { 1086b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return mNameLookupCandidates.isEmpty(); 1087b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1088b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1089b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public String getSelection() { 1090b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelection.setLength(mSelection.length() - 1); // Strip last comma 1091b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelection.append(')'); 1092b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return mSelection.toString(); 1093b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1094b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1095b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public int getLookupType(String name) { 1096b94bfa502569ce869d443353c174d02754d42a82Zheng Fu for (int i = 0; i < mNameLookupCandidates.mCount; i++) { 1097b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (mNameLookupCandidates.mList.get(i).mName.equals(name)) { 1098b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return mNameLookupCandidates.mList.get(i).mLookupType; 1099b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1100b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1101b94bfa502569ce869d443353c174d02754d42a82Zheng Fu throw new IllegalStateException(); 1102b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1103b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1104b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1105b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1106b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Finds contacts with names matching the specified name. 1107b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 11083a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final void updateMatchScoresBasedOnNameMatches(SQLiteDatabase db, String query, 1109b94bfa502569ce869d443353c174d02754d42a82Zheng Fu MatchCandidateList candidates, ContactMatcher matcher) { 1110b94bfa502569ce869d443353c174d02754d42a82Zheng Fu candidates.clear(); 1111b94bfa502569ce869d443353c174d02754d42a82Zheng Fu NameLookupSelectionBuilder builder = new NameLookupSelectionBuilder( 1112b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mNameSplitter, candidates); 1113b94bfa502569ce869d443353c174d02754d42a82Zheng Fu builder.insertNameLookup(0, 0, query, FullNameStyle.UNDEFINED); 1114b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (builder.isEmpty()) { 1115b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 1116b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1117b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1118b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Cursor c = db.query(NameLookupMatchQueryWithParameter.TABLE, 1119b94bfa502569ce869d443353c174d02754d42a82Zheng Fu NameLookupMatchQueryWithParameter.COLUMNS, builder.getSelection(), null, null, null, 1120b94bfa502569ce869d443353c174d02754d42a82Zheng Fu null, PRIMARY_HIT_LIMIT_STRING); 1121b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 1122b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (c.moveToNext()) { 1123b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long contactId = c.getLong(NameLookupMatchQueryWithParameter.CONTACT_ID); 1124b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String name = c.getString(NameLookupMatchQueryWithParameter.NAME); 1125b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int nameTypeA = builder.getLookupType(name); 1126b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int nameTypeB = c.getInt(NameLookupMatchQueryWithParameter.NAME_TYPE); 1127b94bfa502569ce869d443353c174d02754d42a82Zheng Fu matcher.matchName(contactId, nameTypeA, name, nameTypeB, name, 1128b94bfa502569ce869d443353c174d02754d42a82Zheng Fu ContactMatcher.MATCHING_ALGORITHM_EXACT); 1129b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (nameTypeA == NameLookupType.NICKNAME && nameTypeB == NameLookupType.NICKNAME) { 1130b94bfa502569ce869d443353c174d02754d42a82Zheng Fu matcher.updateScoreWithNicknameMatch(contactId); 1131b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1132b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1133b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 1134b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.close(); 1135b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1136b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1137b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1138aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected interface EmailLookupQuery { 1139b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String TABLE = Tables.DATA + " dataA" 1140b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " JOIN " + Tables.DATA + " dataB" + 1141d0d961e19f19704f7967dadf5be61fe6273a1d32Zheng Fu " ON dataA." + Email.DATA + "= dataB." + Email.DATA 1142b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " JOIN " + Tables.RAW_CONTACTS + 1143b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " ON (dataB." + Data.RAW_CONTACT_ID + " = " 1144b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Tables.RAW_CONTACTS + "." + RawContacts._ID + ")"; 1145b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1146b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String SELECTION = "dataA." + Data.RAW_CONTACT_ID + "=?1" 1147b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND dataA." + DataColumns.MIMETYPE_ID + "=?2" 1148b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND dataA." + Email.DATA + " NOT NULL" 1149b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND dataB." + DataColumns.MIMETYPE_ID + "=?2" 1150b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + RawContactsColumns.AGGREGATION_NEEDED + "=0" 1151b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + RawContacts.CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY; 1152b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1153b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String[] COLUMNS = new String[] { 1154aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu Tables.RAW_CONTACTS + "." + RawContacts._ID, 1155aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu RawContacts.CONTACT_ID, 1156aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu RawContactsColumns.ACCOUNT_ID 1157b94bfa502569ce869d443353c174d02754d42a82Zheng Fu }; 1158b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1159aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int RAW_CONTACT_ID = 0; 1160aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int CONTACT_ID = 1; 1161aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int ACCOUNT_ID = 2; 1162b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1163b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1164aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected interface PhoneLookupQuery { 1165b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String TABLE = Tables.PHONE_LOOKUP + " phoneA" 1166b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " JOIN " + Tables.DATA + " dataA" 1167b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " ON (dataA." + Data._ID + "=phoneA." + PhoneLookupColumns.DATA_ID + ")" 1168b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " JOIN " + Tables.PHONE_LOOKUP + " phoneB" 1169b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " ON (phoneA." + PhoneLookupColumns.MIN_MATCH + "=" 1170b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + "phoneB." + PhoneLookupColumns.MIN_MATCH + ")" 1171b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " JOIN " + Tables.DATA + " dataB" 1172b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " ON (dataB." + Data._ID + "=phoneB." + PhoneLookupColumns.DATA_ID + ")" 1173b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " JOIN " + Tables.RAW_CONTACTS 1174b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " ON (dataB." + Data.RAW_CONTACT_ID + " = " 1175b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Tables.RAW_CONTACTS + "." + RawContacts._ID + ")"; 1176b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1177b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String SELECTION = "dataA." + Data.RAW_CONTACT_ID + "=?" 1178b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND PHONE_NUMBERS_EQUAL(dataA." + Phone.NUMBER + ", " 1179b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + "dataB." + Phone.NUMBER + ",?)" 1180b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + RawContactsColumns.AGGREGATION_NEEDED + "=0" 1181b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + RawContacts.CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY; 1182b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1183b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String[] COLUMNS = new String[] { 1184aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu Tables.RAW_CONTACTS + "." + RawContacts._ID, 1185aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu RawContacts.CONTACT_ID, 1186aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu RawContactsColumns.ACCOUNT_ID 1187b94bfa502569ce869d443353c174d02754d42a82Zheng Fu }; 1188b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1189aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int RAW_CONTACT_ID = 0; 1190aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int CONTACT_ID = 1; 1191aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu int ACCOUNT_ID = 2; 1192b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1193b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1194b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private interface ContactNameLookupQuery { 1195b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS; 1196b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1197aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu String[] COLUMNS = new String[]{ 1198b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContacts.CONTACT_ID, 1199b94bfa502569ce869d443353c174d02754d42a82Zheng Fu NameLookupColumns.NORMALIZED_NAME, 1200b94bfa502569ce869d443353c174d02754d42a82Zheng Fu NameLookupColumns.NAME_TYPE 1201b94bfa502569ce869d443353c174d02754d42a82Zheng Fu }; 1202b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1203b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int CONTACT_ID = 0; 1204b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int NORMALIZED_NAME = 1; 1205b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int NAME_TYPE = 2; 1206b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1207b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1208b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1209b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Loads all candidate rows from the name lookup table and updates match scores based 1210b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * on that data. 1211b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 1212b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private void matchAllCandidates(SQLiteDatabase db, String selection, 1213b94bfa502569ce869d443353c174d02754d42a82Zheng Fu MatchCandidateList candidates, ContactMatcher matcher, int algorithm, String limit) { 1214b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final Cursor c = db.query(ContactNameLookupQuery.TABLE, ContactNameLookupQuery.COLUMNS, 1215b94bfa502569ce869d443353c174d02754d42a82Zheng Fu selection, null, null, null, null, limit); 1216b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1217b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 1218b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (c.moveToNext()) { 1219b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Long contactId = c.getLong(ContactNameLookupQuery.CONTACT_ID); 1220b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String name = c.getString(ContactNameLookupQuery.NORMALIZED_NAME); 1221b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int nameType = c.getInt(ContactNameLookupQuery.NAME_TYPE); 1222b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1223b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Note the N^2 complexity of the following fragment. This is not a huge concern 1224b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // since the number of candidates is very small and in general secondary hits 1225b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // in the absence of primary hits are rare. 1226b94bfa502569ce869d443353c174d02754d42a82Zheng Fu for (int i = 0; i < candidates.mCount; i++) { 1227b94bfa502569ce869d443353c174d02754d42a82Zheng Fu NameMatchCandidate candidate = candidates.mList.get(i); 1228b94bfa502569ce869d443353c174d02754d42a82Zheng Fu matcher.matchName(contactId, candidate.mLookupType, candidate.mName, 1229b94bfa502569ce869d443353c174d02754d42a82Zheng Fu nameType, name, algorithm); 1230b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1231b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1232b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 1233b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.close(); 1234b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1235b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1236b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1237b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private interface RawContactsQuery { 1238b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String SQL_FORMAT_HAS_SUPER_PRIMARY_NAME = 1239b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " EXISTS(SELECT 1 " + 1240b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Tables.DATA + " d " + 1241b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE d." + DataColumns.MIMETYPE_ID + "=%d " + 1242b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d." + Data.RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID + 1243b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d." + Data.IS_SUPER_PRIMARY + "=1)"; 1244b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1245b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String SQL_FORMAT = 1246b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "SELECT " 1247b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContactsColumns.CONCRETE_ID + "," 1248b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContactsColumns.DISPLAY_NAME + "," 1249b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContactsColumns.DISPLAY_NAME_SOURCE + "," 1250b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + AccountsColumns.CONCRETE_ACCOUNT_TYPE + "," 1251b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + AccountsColumns.CONCRETE_ACCOUNT_NAME + "," 1252b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + AccountsColumns.CONCRETE_DATA_SET + "," 1253b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts.SOURCE_ID + "," 1254b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts.CUSTOM_RINGTONE + "," 1255b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts.SEND_TO_VOICEMAIL + "," 1256b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts.LAST_TIME_CONTACTED + "," 1257b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts.TIMES_CONTACTED + "," 1258b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts.STARRED + "," 1259b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts.PINNED + "," 1260b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + DataColumns.CONCRETE_ID + "," 1261b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + DataColumns.CONCRETE_MIMETYPE_ID + "," 1262b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Data.IS_SUPER_PRIMARY + "," 1263b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Photo.PHOTO_FILE_ID + "," 1264b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + SQL_FORMAT_HAS_SUPER_PRIMARY_NAME + 1265b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Tables.RAW_CONTACTS + 1266b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " JOIN " + Tables.ACCOUNTS + " ON (" 1267b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + AccountsColumns.CONCRETE_ID + "=" + RawContactsColumns.CONCRETE_ACCOUNT_ID 1268b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + ")" + 1269b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " LEFT OUTER JOIN " + Tables.DATA + 1270b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " ON (" + DataColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID 1271b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND ((" + DataColumns.MIMETYPE_ID + "=%d" 1272b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + Photo.PHOTO + " NOT NULL)" 1273b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " OR (" + DataColumns.MIMETYPE_ID + "=%d" 1274b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + Phone.NUMBER + " NOT NULL)))"; 1275b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1276b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String SQL_FORMAT_BY_RAW_CONTACT_ID = SQL_FORMAT + 1277b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + RawContactsColumns.CONCRETE_ID + "=?"; 1278b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1279b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String SQL_FORMAT_BY_CONTACT_ID = SQL_FORMAT + 1280b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + RawContacts.CONTACT_ID + "=?" 1281b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + RawContacts.DELETED + "=0"; 1282b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1283b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int RAW_CONTACT_ID = 0; 1284b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int DISPLAY_NAME = 1; 1285b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int DISPLAY_NAME_SOURCE = 2; 1286b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int ACCOUNT_TYPE = 3; 1287b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int ACCOUNT_NAME = 4; 1288b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int DATA_SET = 5; 1289b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int SOURCE_ID = 6; 1290b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int CUSTOM_RINGTONE = 7; 1291b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int SEND_TO_VOICEMAIL = 8; 1292b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int LAST_TIME_CONTACTED = 9; 1293b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int TIMES_CONTACTED = 10; 1294b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int STARRED = 11; 1295b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int PINNED = 12; 1296b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int DATA_ID = 13; 1297b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int MIMETYPE_ID = 14; 1298b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int IS_SUPER_PRIMARY = 15; 1299b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int PHOTO_FILE_ID = 16; 1300b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int HAS_SUPER_PRIMARY_NAME = 17; 1301b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1302b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1303aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected interface ContactReplaceSqlStatement { 1304b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String UPDATE_SQL = 1305b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "UPDATE " + Tables.CONTACTS + 1306b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " SET " 1307b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.NAME_RAW_CONTACT_ID + "=?, " 1308b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.PHOTO_ID + "=?, " 1309b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.PHOTO_FILE_ID + "=?, " 1310b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.SEND_TO_VOICEMAIL + "=?, " 1311b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.CUSTOM_RINGTONE + "=?, " 1312b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.LAST_TIME_CONTACTED + "=?, " 1313b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.TIMES_CONTACTED + "=?, " 1314b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.STARRED + "=?, " 1315b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.PINNED + "=?, " 1316b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.HAS_PHONE_NUMBER + "=?, " 1317b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.LOOKUP_KEY + "=?, " 1318b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + "=? " + 1319b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + Contacts._ID + "=?"; 1320b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1321b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String INSERT_SQL = 1322b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "INSERT INTO " + Tables.CONTACTS + " (" 1323b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.NAME_RAW_CONTACT_ID + ", " 1324b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.PHOTO_ID + ", " 1325b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.PHOTO_FILE_ID + ", " 1326b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.SEND_TO_VOICEMAIL + ", " 1327b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.CUSTOM_RINGTONE + ", " 1328b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.LAST_TIME_CONTACTED + ", " 1329b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.TIMES_CONTACTED + ", " 1330b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.STARRED + ", " 1331b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.PINNED + ", " 1332b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.HAS_PHONE_NUMBER + ", " 1333b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.LOOKUP_KEY + ", " 1334b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Contacts.CONTACT_LAST_UPDATED_TIMESTAMP 1335b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + ") " + 1336b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"; 1337b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1338b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int NAME_RAW_CONTACT_ID = 1; 1339b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int PHOTO_ID = 2; 1340b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int PHOTO_FILE_ID = 3; 1341b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int SEND_TO_VOICEMAIL = 4; 1342b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int CUSTOM_RINGTONE = 5; 1343b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int LAST_TIME_CONTACTED = 6; 1344b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int TIMES_CONTACTED = 7; 1345b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int STARRED = 8; 1346b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int PINNED = 9; 1347b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int HAS_PHONE_NUMBER = 10; 1348b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int LOOKUP_KEY = 11; 1349b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int CONTACT_LAST_UPDATED_TIMESTAMP = 12; 1350b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int CONTACT_ID = 13; 1351b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1352b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1353b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1354b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Computes aggregate-level data for the specified aggregate contact ID. 1355b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 1356aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected void computeAggregateData(SQLiteDatabase db, long contactId, 1357b94bfa502569ce869d443353c174d02754d42a82Zheng Fu SQLiteStatement statement) { 1358b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelectionArgs1[0] = String.valueOf(contactId); 1359b94bfa502569ce869d443353c174d02754d42a82Zheng Fu computeAggregateData(db, mRawContactsQueryByContactId, mSelectionArgs1, statement); 1360b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1361b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1362b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1363b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Indicates whether the given photo entry and priority gives this photo a higher overall 1364b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * priority than the current best photo entry and priority. 1365b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 1366b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private boolean hasHigherPhotoPriority(PhotoEntry photoEntry, int priority, 1367b94bfa502569ce869d443353c174d02754d42a82Zheng Fu PhotoEntry bestPhotoEntry, int bestPriority) { 1368b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int photoComparison = photoEntry.compareTo(bestPhotoEntry); 1369b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return photoComparison < 0 || photoComparison == 0 && priority > bestPriority; 1370b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1371b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1372b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1373b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Computes aggregate-level data from constituent raw contacts. 1374b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 13753a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki protected final void computeAggregateData(final SQLiteDatabase db, String sql, String[] sqlArgs, 1376b94bfa502569ce869d443353c174d02754d42a82Zheng Fu SQLiteStatement statement) { 1377b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long currentRawContactId = -1; 1378b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long bestPhotoId = -1; 1379b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long bestPhotoFileId = 0; 1380b94bfa502569ce869d443353c174d02754d42a82Zheng Fu PhotoEntry bestPhotoEntry = null; 1381b94bfa502569ce869d443353c174d02754d42a82Zheng Fu boolean foundSuperPrimaryPhoto = false; 1382b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int photoPriority = -1; 1383b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int totalRowCount = 0; 1384b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int contactSendToVoicemail = 0; 1385b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String contactCustomRingtone = null; 1386b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long contactLastTimeContacted = 0; 1387b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int contactTimesContacted = 0; 1388b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int contactStarred = 0; 1389b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int contactPinned = Integer.MAX_VALUE; 1390b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int hasPhoneNumber = 0; 1391b94bfa502569ce869d443353c174d02754d42a82Zheng Fu StringBuilder lookupKey = new StringBuilder(); 1392b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1393b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameCandidate.clear(); 1394b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1395b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Cursor c = db.rawQuery(sql, sqlArgs); 1396b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 1397b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (c.moveToNext()) { 1398b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long rawContactId = c.getLong(RawContactsQuery.RAW_CONTACT_ID); 1399b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (rawContactId != currentRawContactId) { 1400b94bfa502569ce869d443353c174d02754d42a82Zheng Fu currentRawContactId = rawContactId; 1401b94bfa502569ce869d443353c174d02754d42a82Zheng Fu totalRowCount++; 1402b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1403b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Assemble sub-account. 1404b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String accountType = c.getString(RawContactsQuery.ACCOUNT_TYPE); 1405b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String dataSet = c.getString(RawContactsQuery.DATA_SET); 1406b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String accountWithDataSet = (!TextUtils.isEmpty(dataSet)) 1407b94bfa502569ce869d443353c174d02754d42a82Zheng Fu ? accountType + "/" + dataSet 1408b94bfa502569ce869d443353c174d02754d42a82Zheng Fu : accountType; 1409b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1410b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Display name 1411b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String displayName = c.getString(RawContactsQuery.DISPLAY_NAME); 1412b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int displayNameSource = c.getInt(RawContactsQuery.DISPLAY_NAME_SOURCE); 1413b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int isNameSuperPrimary = c.getInt(RawContactsQuery.HAS_SUPER_PRIMARY_NAME); 1414b94bfa502569ce869d443353c174d02754d42a82Zheng Fu processDisplayNameCandidate(rawContactId, displayName, displayNameSource, 1415b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactsProvider.isWritableAccountWithDataSet(accountWithDataSet), 1416b94bfa502569ce869d443353c174d02754d42a82Zheng Fu isNameSuperPrimary != 0); 1417b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1418b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Contact options 1419b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (!c.isNull(RawContactsQuery.SEND_TO_VOICEMAIL)) { 1420b94bfa502569ce869d443353c174d02754d42a82Zheng Fu boolean sendToVoicemail = 1421b94bfa502569ce869d443353c174d02754d42a82Zheng Fu (c.getInt(RawContactsQuery.SEND_TO_VOICEMAIL) != 0); 1422b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (sendToVoicemail) { 1423b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactSendToVoicemail++; 1424b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1425b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1426b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1427b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (contactCustomRingtone == null 1428b94bfa502569ce869d443353c174d02754d42a82Zheng Fu && !c.isNull(RawContactsQuery.CUSTOM_RINGTONE)) { 1429b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactCustomRingtone = c.getString(RawContactsQuery.CUSTOM_RINGTONE); 1430b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1431b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1432b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long lastTimeContacted = c.getLong(RawContactsQuery.LAST_TIME_CONTACTED); 1433b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (lastTimeContacted > contactLastTimeContacted) { 1434b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactLastTimeContacted = lastTimeContacted; 1435b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1436b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1437b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int timesContacted = c.getInt(RawContactsQuery.TIMES_CONTACTED); 1438b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (timesContacted > contactTimesContacted) { 1439b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactTimesContacted = timesContacted; 1440b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1441b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1442b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (c.getInt(RawContactsQuery.STARRED) != 0) { 1443b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactStarred = 1; 1444b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1445b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1446b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // contactPinned should be the lowest value of its constituent raw contacts, 1447b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // excluding negative integers 1448b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final int rawContactPinned = c.getInt(RawContactsQuery.PINNED); 1449b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (rawContactPinned > PinnedPositions.UNPINNED) { 1450b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactPinned = Math.min(contactPinned, rawContactPinned); 1451b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1452b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1453b94bfa502569ce869d443353c174d02754d42a82Zheng Fu appendLookupKey( 1454b94bfa502569ce869d443353c174d02754d42a82Zheng Fu lookupKey, 1455b94bfa502569ce869d443353c174d02754d42a82Zheng Fu accountWithDataSet, 1456b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.getString(RawContactsQuery.ACCOUNT_NAME), 1457b94bfa502569ce869d443353c174d02754d42a82Zheng Fu rawContactId, 1458b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.getString(RawContactsQuery.SOURCE_ID), 1459b94bfa502569ce869d443353c174d02754d42a82Zheng Fu displayName); 1460b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1461b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1462b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (!c.isNull(RawContactsQuery.DATA_ID)) { 1463b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long dataId = c.getLong(RawContactsQuery.DATA_ID); 1464b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long photoFileId = c.getLong(RawContactsQuery.PHOTO_FILE_ID); 1465b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int mimetypeId = c.getInt(RawContactsQuery.MIMETYPE_ID); 1466b94bfa502569ce869d443353c174d02754d42a82Zheng Fu boolean superPrimary = c.getInt(RawContactsQuery.IS_SUPER_PRIMARY) != 0; 1467b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (mimetypeId == mMimeTypeIdPhoto) { 1468b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (!foundSuperPrimaryPhoto) { 1469b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Lookup the metadata for the photo, if available. Note that data set 1470b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // does not come into play here, since accounts are looked up in the 1471b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // account manager in the priority resolver. 1472b94bfa502569ce869d443353c174d02754d42a82Zheng Fu PhotoEntry photoEntry = getPhotoMetadata(db, photoFileId); 1473b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String accountType = c.getString(RawContactsQuery.ACCOUNT_TYPE); 1474b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int priority = mPhotoPriorityResolver.getPhotoPriority(accountType); 1475b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (superPrimary || hasHigherPhotoPriority( 1476b94bfa502569ce869d443353c174d02754d42a82Zheng Fu photoEntry, priority, bestPhotoEntry, photoPriority)) { 1477b94bfa502569ce869d443353c174d02754d42a82Zheng Fu bestPhotoEntry = photoEntry; 1478b94bfa502569ce869d443353c174d02754d42a82Zheng Fu photoPriority = priority; 1479b94bfa502569ce869d443353c174d02754d42a82Zheng Fu bestPhotoId = dataId; 1480b94bfa502569ce869d443353c174d02754d42a82Zheng Fu bestPhotoFileId = photoFileId; 1481b94bfa502569ce869d443353c174d02754d42a82Zheng Fu foundSuperPrimaryPhoto |= superPrimary; 1482b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1483b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1484b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else if (mimetypeId == mMimeTypeIdPhone) { 1485b94bfa502569ce869d443353c174d02754d42a82Zheng Fu hasPhoneNumber = 1; 1486b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1487b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1488b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1489b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 1490b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.close(); 1491b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1492b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1493b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (contactPinned == Integer.MAX_VALUE) { 1494b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactPinned = PinnedPositions.UNPINNED; 1495b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1496b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1497b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindLong(ContactReplaceSqlStatement.NAME_RAW_CONTACT_ID, 1498b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameCandidate.rawContactId); 1499b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1500b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (bestPhotoId != -1) { 1501b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindLong(ContactReplaceSqlStatement.PHOTO_ID, bestPhotoId); 1502b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else { 1503b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindNull(ContactReplaceSqlStatement.PHOTO_ID); 1504b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1505b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1506b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (bestPhotoFileId != 0) { 1507b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindLong(ContactReplaceSqlStatement.PHOTO_FILE_ID, bestPhotoFileId); 1508b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else { 1509b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindNull(ContactReplaceSqlStatement.PHOTO_FILE_ID); 1510b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1511b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1512b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindLong(ContactReplaceSqlStatement.SEND_TO_VOICEMAIL, 1513b94bfa502569ce869d443353c174d02754d42a82Zheng Fu totalRowCount == contactSendToVoicemail ? 1 : 0); 1514b94bfa502569ce869d443353c174d02754d42a82Zheng Fu DatabaseUtils.bindObjectToProgram(statement, ContactReplaceSqlStatement.CUSTOM_RINGTONE, 1515b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactCustomRingtone); 1516b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindLong(ContactReplaceSqlStatement.LAST_TIME_CONTACTED, 1517b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactLastTimeContacted); 1518b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindLong(ContactReplaceSqlStatement.TIMES_CONTACTED, 1519b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactTimesContacted); 1520b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindLong(ContactReplaceSqlStatement.STARRED, 1521b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactStarred); 1522b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindLong(ContactReplaceSqlStatement.PINNED, 1523b94bfa502569ce869d443353c174d02754d42a82Zheng Fu contactPinned); 1524b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindLong(ContactReplaceSqlStatement.HAS_PHONE_NUMBER, 1525b94bfa502569ce869d443353c174d02754d42a82Zheng Fu hasPhoneNumber); 1526b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindString(ContactReplaceSqlStatement.LOOKUP_KEY, 1527b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Uri.encode(lookupKey.toString())); 1528b94bfa502569ce869d443353c174d02754d42a82Zheng Fu statement.bindLong(ContactReplaceSqlStatement.CONTACT_LAST_UPDATED_TIMESTAMP, 1529b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Clock.getInstance().currentTimeMillis()); 1530b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1531b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1532b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1533b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Builds a lookup key using the given data. 1534b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 15353a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki // Overridden by ProfileAggregator. 1536b94bfa502569ce869d443353c174d02754d42a82Zheng Fu protected void appendLookupKey(StringBuilder sb, String accountTypeWithDataSet, 1537b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String accountName, long rawContactId, String sourceId, String displayName) { 1538b94bfa502569ce869d443353c174d02754d42a82Zheng Fu ContactLookupKey.appendToLookupKey(sb, accountTypeWithDataSet, accountName, rawContactId, 1539b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sourceId, displayName); 1540b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1541b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1542b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1543b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Uses the supplied values to determine if they represent a "better" display name 1544b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * for the aggregate contact currently evaluated. If so, it updates 1545b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * {@link #mDisplayNameCandidate} with the new values. 1546b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 1547b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private void processDisplayNameCandidate(long rawContactId, String displayName, 1548b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int displayNameSource, boolean writableAccount, boolean isNameSuperPrimary) { 1549b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1550b94bfa502569ce869d443353c174d02754d42a82Zheng Fu boolean replace = false; 1551b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (mDisplayNameCandidate.rawContactId == -1) { 1552b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // No previous values available 1553b94bfa502569ce869d443353c174d02754d42a82Zheng Fu replace = true; 1554b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else if (!TextUtils.isEmpty(displayName)) { 1555b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (isNameSuperPrimary) { 1556b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // A super primary name is better than any other name 1557b94bfa502569ce869d443353c174d02754d42a82Zheng Fu replace = true; 1558b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else if (mDisplayNameCandidate.isNameSuperPrimary == isNameSuperPrimary) { 1559b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (mDisplayNameCandidate.displayNameSource < displayNameSource) { 1560b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // New values come from an superior source, e.g. structured name vs phone number 1561b94bfa502569ce869d443353c174d02754d42a82Zheng Fu replace = true; 1562b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else if (mDisplayNameCandidate.displayNameSource == displayNameSource) { 1563b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (!mDisplayNameCandidate.writableAccount && writableAccount) { 1564b94bfa502569ce869d443353c174d02754d42a82Zheng Fu replace = true; 1565b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else if (mDisplayNameCandidate.writableAccount == writableAccount) { 1566b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (NameNormalizer.compareComplexity(displayName, 1567b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameCandidate.displayName) > 0) { 1568b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // New name is more complex than the previously found one 1569b94bfa502569ce869d443353c174d02754d42a82Zheng Fu replace = true; 1570b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1571b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1572b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1573b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1574b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1575b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1576b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (replace) { 1577b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameCandidate.rawContactId = rawContactId; 1578b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameCandidate.displayName = displayName; 1579b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameCandidate.displayNameSource = displayNameSource; 1580b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameCandidate.isNameSuperPrimary = isNameSuperPrimary; 1581b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameCandidate.writableAccount = writableAccount; 1582b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1583b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1584b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1585b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private interface PhotoIdQuery { 1586b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final String[] COLUMNS = new String[] { 1587b94bfa502569ce869d443353c174d02754d42a82Zheng Fu AccountsColumns.CONCRETE_ACCOUNT_TYPE, 1588b94bfa502569ce869d443353c174d02754d42a82Zheng Fu DataColumns.CONCRETE_ID, 1589b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Data.IS_SUPER_PRIMARY, 1590b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Photo.PHOTO_FILE_ID, 1591b94bfa502569ce869d443353c174d02754d42a82Zheng Fu }; 1592b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1593b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int ACCOUNT_TYPE = 0; 1594b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int DATA_ID = 1; 1595b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int IS_SUPER_PRIMARY = 2; 1596b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int PHOTO_FILE_ID = 3; 1597b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1598b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 15993a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void updatePhotoId(SQLiteDatabase db, long rawContactId) { 1600b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1601b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long contactId = mDbHelper.getContactId(rawContactId); 1602b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (contactId == 0) { 1603b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 1604b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1605b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1606b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long bestPhotoId = -1; 1607b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long bestPhotoFileId = 0; 1608b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int photoPriority = -1; 1609b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1610b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long photoMimeType = mDbHelper.getMimeTypeId(Photo.CONTENT_ITEM_TYPE); 1611b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1612b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String tables = Tables.RAW_CONTACTS 1613b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " JOIN " + Tables.ACCOUNTS + " ON (" 1614b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + AccountsColumns.CONCRETE_ID + "=" + RawContactsColumns.CONCRETE_ACCOUNT_ID 1615b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + ")" 1616b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " JOIN " + Tables.DATA + " ON(" 1617b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + DataColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID 1618b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND (" + DataColumns.MIMETYPE_ID + "=" + photoMimeType + " AND " 1619b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + Photo.PHOTO + " NOT NULL))"; 1620b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1621b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelectionArgs1[0] = String.valueOf(contactId); 1622b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final Cursor c = db.query(tables, PhotoIdQuery.COLUMNS, 1623b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContacts.CONTACT_ID + "=?", mSelectionArgs1, null, null, null); 1624b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 1625b94bfa502569ce869d443353c174d02754d42a82Zheng Fu PhotoEntry bestPhotoEntry = null; 1626b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (c.moveToNext()) { 1627b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long dataId = c.getLong(PhotoIdQuery.DATA_ID); 1628b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long photoFileId = c.getLong(PhotoIdQuery.PHOTO_FILE_ID); 1629b94bfa502569ce869d443353c174d02754d42a82Zheng Fu boolean superPrimary = c.getInt(PhotoIdQuery.IS_SUPER_PRIMARY) != 0; 1630b94bfa502569ce869d443353c174d02754d42a82Zheng Fu PhotoEntry photoEntry = getPhotoMetadata(db, photoFileId); 1631b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1632b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Note that data set does not come into play here, since accounts are looked up in 1633b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // the account manager in the priority resolver. 1634b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String accountType = c.getString(PhotoIdQuery.ACCOUNT_TYPE); 1635b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int priority = mPhotoPriorityResolver.getPhotoPriority(accountType); 1636b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (superPrimary || hasHigherPhotoPriority( 1637b94bfa502569ce869d443353c174d02754d42a82Zheng Fu photoEntry, priority, bestPhotoEntry, photoPriority)) { 1638b94bfa502569ce869d443353c174d02754d42a82Zheng Fu bestPhotoEntry = photoEntry; 1639b94bfa502569ce869d443353c174d02754d42a82Zheng Fu photoPriority = priority; 1640b94bfa502569ce869d443353c174d02754d42a82Zheng Fu bestPhotoId = dataId; 1641b94bfa502569ce869d443353c174d02754d42a82Zheng Fu bestPhotoFileId = photoFileId; 1642b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (superPrimary) { 1643b94bfa502569ce869d443353c174d02754d42a82Zheng Fu break; 1644b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1645b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1646b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1647b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 1648b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.close(); 1649b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1650b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1651b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (bestPhotoId == -1) { 1652b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPhotoIdUpdate.bindNull(1); 1653b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else { 1654b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPhotoIdUpdate.bindLong(1, bestPhotoId); 1655b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1656b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1657b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (bestPhotoFileId == 0) { 1658b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPhotoIdUpdate.bindNull(2); 1659b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else { 1660b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPhotoIdUpdate.bindLong(2, bestPhotoFileId); 1661b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1662b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1663b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPhotoIdUpdate.bindLong(3, contactId); 1664b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPhotoIdUpdate.execute(); 1665b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1666b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1667b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private interface PhotoFileQuery { 1668b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final String[] COLUMNS = new String[] { 1669b94bfa502569ce869d443353c174d02754d42a82Zheng Fu PhotoFiles.HEIGHT, 1670b94bfa502569ce869d443353c174d02754d42a82Zheng Fu PhotoFiles.WIDTH, 1671b94bfa502569ce869d443353c174d02754d42a82Zheng Fu PhotoFiles.FILESIZE 1672b94bfa502569ce869d443353c174d02754d42a82Zheng Fu }; 1673b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1674b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int HEIGHT = 0; 1675b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int WIDTH = 1; 1676b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int FILESIZE = 2; 1677b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1678b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1679b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private class PhotoEntry implements Comparable<PhotoEntry> { 1680b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Pixel count (width * height) for the image. 1681b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final int pixelCount; 1682b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1683b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // File size (in bytes) of the image. Not populated if the image is a thumbnail. 1684b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final int fileSize; 1685b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1686b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private PhotoEntry(int pixelCount, int fileSize) { 1687b94bfa502569ce869d443353c174d02754d42a82Zheng Fu this.pixelCount = pixelCount; 1688b94bfa502569ce869d443353c174d02754d42a82Zheng Fu this.fileSize = fileSize; 1689b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1690b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1691b94bfa502569ce869d443353c174d02754d42a82Zheng Fu @Override 1692b94bfa502569ce869d443353c174d02754d42a82Zheng Fu public int compareTo(PhotoEntry pe) { 1693b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (pe == null) { 1694b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return -1; 1695b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1696b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (pixelCount == pe.pixelCount) { 1697b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return pe.fileSize - fileSize; 1698b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else { 1699b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return pe.pixelCount - pixelCount; 1700b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1701b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1702b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1703b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1704b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private PhotoEntry getPhotoMetadata(SQLiteDatabase db, long photoFileId) { 1705b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (photoFileId == 0) { 1706b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Assume standard thumbnail size. Don't bother getting a file size for priority; 1707b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // we should fall back to photo priority resolver if all we have are thumbnails. 1708b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int thumbDim = mContactsProvider.getMaxThumbnailDim(); 1709b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return new PhotoEntry(thumbDim * thumbDim, 0); 1710b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else { 1711b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Cursor c = db.query(Tables.PHOTO_FILES, PhotoFileQuery.COLUMNS, PhotoFiles._ID + "=?", 1712b94bfa502569ce869d443353c174d02754d42a82Zheng Fu new String[]{String.valueOf(photoFileId)}, null, null, null); 1713b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 1714b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (c.getCount() == 1) { 1715b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.moveToFirst(); 1716b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int pixelCount = 1717b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.getInt(PhotoFileQuery.HEIGHT) * c.getInt(PhotoFileQuery.WIDTH); 1718b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return new PhotoEntry(pixelCount, c.getInt(PhotoFileQuery.FILESIZE)); 1719b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1720b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 1721b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.close(); 1722b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1723b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1724b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return new PhotoEntry(0, 0); 1725b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1726b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1727b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private interface DisplayNameQuery { 1728b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String SQL_HAS_SUPER_PRIMARY_NAME = 1729b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " EXISTS(SELECT 1 " + 1730b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Tables.DATA + " d " + 1731b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE d." + DataColumns.MIMETYPE_ID + "=? " + 1732b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d." + Data.RAW_CONTACT_ID + "=" + Views.RAW_CONTACTS 1733b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + "." + RawContacts._ID + 1734b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " AND d." + Data.IS_SUPER_PRIMARY + "=1)"; 1735b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1736b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String SQL = 1737b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "SELECT " 1738b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts._ID + "," 1739b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContactsColumns.DISPLAY_NAME + "," 1740b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContactsColumns.DISPLAY_NAME_SOURCE + "," 1741b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + SQL_HAS_SUPER_PRIMARY_NAME + "," 1742b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts.SOURCE_ID + "," 1743b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + RawContacts.ACCOUNT_TYPE_AND_DATA_SET + 1744b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " FROM " + Views.RAW_CONTACTS + 1745b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + RawContacts.CONTACT_ID + "=? "; 1746b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1747b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int _ID = 0; 1748b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int DISPLAY_NAME = 1; 1749b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int DISPLAY_NAME_SOURCE = 2; 1750b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int HAS_SUPER_PRIMARY_NAME = 3; 1751b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int SOURCE_ID = 4; 1752b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int ACCOUNT_TYPE_AND_DATA_SET = 5; 1753b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1754b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 17553a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void updateDisplayNameForRawContact(SQLiteDatabase db, long rawContactId) { 1756b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long contactId = mDbHelper.getContactId(rawContactId); 1757b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (contactId == 0) { 1758b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 1759b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1760b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1761b94bfa502569ce869d443353c174d02754d42a82Zheng Fu updateDisplayNameForContact(db, contactId); 1762b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1763b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 17643a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void updateDisplayNameForContact(SQLiteDatabase db, long contactId) { 1765b94bfa502569ce869d443353c174d02754d42a82Zheng Fu boolean lookupKeyUpdateNeeded = false; 1766b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1767b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameCandidate.clear(); 1768b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1769b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelectionArgs2[0] = String.valueOf(mDbHelper.getMimeTypeIdForStructuredName()); 1770b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelectionArgs2[1] = String.valueOf(contactId); 1771b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final Cursor c = db.rawQuery(DisplayNameQuery.SQL, mSelectionArgs2); 1772b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 1773b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (c.moveToNext()) { 1774b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long rawContactId = c.getLong(DisplayNameQuery._ID); 1775b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String displayName = c.getString(DisplayNameQuery.DISPLAY_NAME); 1776b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int displayNameSource = c.getInt(DisplayNameQuery.DISPLAY_NAME_SOURCE); 1777b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int isNameSuperPrimary = c.getInt(DisplayNameQuery.HAS_SUPER_PRIMARY_NAME); 1778b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String accountTypeAndDataSet = c.getString( 1779b94bfa502569ce869d443353c174d02754d42a82Zheng Fu DisplayNameQuery.ACCOUNT_TYPE_AND_DATA_SET); 1780b94bfa502569ce869d443353c174d02754d42a82Zheng Fu processDisplayNameCandidate(rawContactId, displayName, displayNameSource, 1781b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactsProvider.isWritableAccountWithDataSet(accountTypeAndDataSet), 1782b94bfa502569ce869d443353c174d02754d42a82Zheng Fu isNameSuperPrimary != 0); 1783b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1784b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // If the raw contact has no source id, the lookup key is based on the display 1785b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // name, so the lookup key needs to be updated. 1786b94bfa502569ce869d443353c174d02754d42a82Zheng Fu lookupKeyUpdateNeeded |= c.isNull(DisplayNameQuery.SOURCE_ID); 1787b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1788b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 1789b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.close(); 1790b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1791b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1792b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (mDisplayNameCandidate.rawContactId != -1) { 1793b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameUpdate.bindLong(1, mDisplayNameCandidate.rawContactId); 1794b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameUpdate.bindLong(2, contactId); 1795b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mDisplayNameUpdate.execute(); 1796b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1797b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1798b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (lookupKeyUpdateNeeded) { 1799b94bfa502569ce869d443353c174d02754d42a82Zheng Fu updateLookupKeyForContact(db, contactId); 1800b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1801b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1802b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1803b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1804b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1805b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Updates the {@link Contacts#HAS_PHONE_NUMBER} flag for the aggregate contact containing the 1806b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * specified raw contact. 1807b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 18083a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void updateHasPhoneNumber(SQLiteDatabase db, long rawContactId) { 1809b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1810b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long contactId = mDbHelper.getContactId(rawContactId); 1811b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (contactId == 0) { 1812b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 1813b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1814b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1815b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final SQLiteStatement hasPhoneNumberUpdate = db.compileStatement( 1816b94bfa502569ce869d443353c174d02754d42a82Zheng Fu "UPDATE " + Tables.CONTACTS + 1817b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " SET " + Contacts.HAS_PHONE_NUMBER + "=" 1818b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + "(SELECT (CASE WHEN COUNT(*)=0 THEN 0 ELSE 1 END)" 1819b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " FROM " + Tables.DATA_JOIN_RAW_CONTACTS 1820b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " WHERE " + DataColumns.MIMETYPE_ID + "=?" 1821b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + Phone.NUMBER + " NOT NULL" 1822b94bfa502569ce869d443353c174d02754d42a82Zheng Fu + " AND " + RawContacts.CONTACT_ID + "=?)" + 1823b94bfa502569ce869d443353c174d02754d42a82Zheng Fu " WHERE " + Contacts._ID + "=?"); 1824b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 1825b94bfa502569ce869d443353c174d02754d42a82Zheng Fu hasPhoneNumberUpdate.bindLong(1, mDbHelper.getMimeTypeId(Phone.CONTENT_ITEM_TYPE)); 1826b94bfa502569ce869d443353c174d02754d42a82Zheng Fu hasPhoneNumberUpdate.bindLong(2, contactId); 1827b94bfa502569ce869d443353c174d02754d42a82Zheng Fu hasPhoneNumberUpdate.bindLong(3, contactId); 1828b94bfa502569ce869d443353c174d02754d42a82Zheng Fu hasPhoneNumberUpdate.execute(); 1829b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 1830b94bfa502569ce869d443353c174d02754d42a82Zheng Fu hasPhoneNumberUpdate.close(); 1831b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1832b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1833b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1834b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private interface LookupKeyQuery { 1835b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String TABLE = Views.RAW_CONTACTS; 1836b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String[] COLUMNS = new String[] { 1837b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContacts._ID, 1838b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContactsColumns.DISPLAY_NAME, 1839b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 1840b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContacts.ACCOUNT_NAME, 1841b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContacts.SOURCE_ID, 1842b94bfa502569ce869d443353c174d02754d42a82Zheng Fu }; 1843b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1844b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int ID = 0; 1845b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int DISPLAY_NAME = 1; 1846b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int ACCOUNT_TYPE_AND_DATA_SET = 2; 1847b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int ACCOUNT_NAME = 3; 1848b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int SOURCE_ID = 4; 1849b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1850b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 18513a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void updateLookupKeyForRawContact(SQLiteDatabase db, long rawContactId) { 1852b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long contactId = mDbHelper.getContactId(rawContactId); 1853b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (contactId == 0) { 1854b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 1855b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1856b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1857b94bfa502569ce869d443353c174d02754d42a82Zheng Fu updateLookupKeyForContact(db, contactId); 1858b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1859b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1860b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private void updateLookupKeyForContact(SQLiteDatabase db, long contactId) { 1861b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String lookupKey = computeLookupKeyForContact(db, contactId); 1862b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1863b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (lookupKey == null) { 1864b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mLookupKeyUpdate.bindNull(1); 1865b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else { 1866b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mLookupKeyUpdate.bindString(1, Uri.encode(lookupKey)); 1867b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1868b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mLookupKeyUpdate.bindLong(2, contactId); 1869b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1870b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mLookupKeyUpdate.execute(); 1871b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1872b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 18733a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki // Overridden by ProfileAggregator. 1874b94bfa502569ce869d443353c174d02754d42a82Zheng Fu protected String computeLookupKeyForContact(SQLiteDatabase db, long contactId) { 1875b94bfa502569ce869d443353c174d02754d42a82Zheng Fu StringBuilder sb = new StringBuilder(); 1876b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mSelectionArgs1[0] = String.valueOf(contactId); 1877b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final Cursor c = db.query(LookupKeyQuery.TABLE, LookupKeyQuery.COLUMNS, 1878b94bfa502569ce869d443353c174d02754d42a82Zheng Fu RawContacts.CONTACT_ID + "=?", mSelectionArgs1, null, null, RawContacts._ID); 1879b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 1880b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (c.moveToNext()) { 1881b94bfa502569ce869d443353c174d02754d42a82Zheng Fu ContactLookupKey.appendToLookupKey(sb, 1882b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.getString(LookupKeyQuery.ACCOUNT_TYPE_AND_DATA_SET), 1883b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.getString(LookupKeyQuery.ACCOUNT_NAME), 1884b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.getLong(LookupKeyQuery.ID), 1885b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.getString(LookupKeyQuery.SOURCE_ID), 1886b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.getString(LookupKeyQuery.DISPLAY_NAME)); 1887b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1888b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 1889b94bfa502569ce869d443353c174d02754d42a82Zheng Fu c.close(); 1890b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1891b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return sb.length() == 0 ? null : sb.toString(); 1892b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1893b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1894b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1895b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Execute {@link SQLiteStatement} that will update the 1896b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * {@link Contacts#STARRED} flag for the given {@link RawContacts#_ID}. 1897b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 18983a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void updateStarred(long rawContactId) { 1899b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long contactId = mDbHelper.getContactId(rawContactId); 1900b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (contactId == 0) { 1901b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 1902b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1903b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1904b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mStarredUpdate.bindLong(1, contactId); 1905b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mStarredUpdate.execute(); 1906b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1907b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1908b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1909b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Execute {@link SQLiteStatement} that will update the 1910b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * {@link Contacts#PINNED} flag for the given {@link RawContacts#_ID}. 1911b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 19123a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final void updatePinned(long rawContactId) { 1913b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long contactId = mDbHelper.getContactId(rawContactId); 1914b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (contactId == 0) { 1915b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return; 1916b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1917b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPinnedUpdate.bindLong(1, contactId); 1918b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mPinnedUpdate.execute(); 1919b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1920b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1921b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1922b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Finds matching contacts and returns a cursor on those. 1923b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 19243a83f4c60fbe7eb2ee31186d0675dcfbac3ee6b5Makoto Onuki public final Cursor queryAggregationSuggestions(SQLiteQueryBuilder qb, 1925b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String[] projection, long contactId, int maxSuggestions, String filter, 1926b94bfa502569ce869d443353c174d02754d42a82Zheng Fu ArrayList<AggregationSuggestionParameter> parameters) { 1927b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 1928b94bfa502569ce869d443353c174d02754d42a82Zheng Fu db.beginTransaction(); 1929b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 1930b94bfa502569ce869d443353c174d02754d42a82Zheng Fu List<MatchScore> bestMatches = findMatchingContacts(db, contactId, parameters); 19315ca831dc33dfa16821647e14e377c484df823c80Zheng Fu List<MatchScore> bestMatchesWithoutDuplicateContactIds = new ArrayList<>(); 19325ca831dc33dfa16821647e14e377c484df823c80Zheng Fu Set<Long> contactIds = new HashSet<>(); 19335ca831dc33dfa16821647e14e377c484df823c80Zheng Fu for (MatchScore bestMatch : bestMatches) { 19345ca831dc33dfa16821647e14e377c484df823c80Zheng Fu long cid = bestMatch.getContactId(); 193563a781313c71c966f9ca44a0cb3c13b477981f52Zheng Fu if (!contactIds.contains(cid) && cid != contactId) { 19365ca831dc33dfa16821647e14e377c484df823c80Zheng Fu bestMatchesWithoutDuplicateContactIds.add(bestMatch); 19375ca831dc33dfa16821647e14e377c484df823c80Zheng Fu contactIds.add(cid); 19385ca831dc33dfa16821647e14e377c484df823c80Zheng Fu } 19395ca831dc33dfa16821647e14e377c484df823c80Zheng Fu } 19405ca831dc33dfa16821647e14e377c484df823c80Zheng Fu return queryMatchingContacts(qb, db, projection, bestMatchesWithoutDuplicateContactIds, 19415ca831dc33dfa16821647e14e377c484df823c80Zheng Fu maxSuggestions, filter); 1942b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 1943b94bfa502569ce869d443353c174d02754d42a82Zheng Fu db.endTransaction(); 1944b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1945b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1946b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1947b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private interface ContactIdQuery { 1948b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String[] COLUMNS = new String[] { 1949b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Contacts._ID 1950b94bfa502569ce869d443353c174d02754d42a82Zheng Fu }; 1951b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1952b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int _ID = 0; 1953b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1954b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1955b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 1956b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Loads contacts with specified IDs and returns them in the order of IDs in the 1957b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * supplied list. 1958b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 1959b94bfa502569ce869d443353c174d02754d42a82Zheng Fu private Cursor queryMatchingContacts(SQLiteQueryBuilder qb, SQLiteDatabase db, 1960b94bfa502569ce869d443353c174d02754d42a82Zheng Fu String[] projection, List<MatchScore> bestMatches, int maxSuggestions, String filter) { 1961b94bfa502569ce869d443353c174d02754d42a82Zheng Fu StringBuilder sb = new StringBuilder(); 1962b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.append(Contacts._ID); 1963b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.append(" IN ("); 1964b94bfa502569ce869d443353c174d02754d42a82Zheng Fu for (int i = 0; i < bestMatches.size(); i++) { 1965b94bfa502569ce869d443353c174d02754d42a82Zheng Fu MatchScore matchScore = bestMatches.get(i); 1966b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (i != 0) { 1967b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.append(","); 1968b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1969b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.append(matchScore.getContactId()); 1970b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1971b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.append(")"); 1972b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1973b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (!TextUtils.isEmpty(filter)) { 1974b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.append(" AND " + Contacts._ID + " IN "); 1975b94bfa502569ce869d443353c174d02754d42a82Zheng Fu mContactsProvider.appendContactFilterAsNestedQuery(sb, filter); 1976b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1977b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1978b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Run a query and find ids of best matching contacts satisfying the filter (if any) 1979b94bfa502569ce869d443353c174d02754d42a82Zheng Fu HashSet<Long> foundIds = new HashSet<Long>(); 1980b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Cursor cursor = db.query(qb.getTables(), ContactIdQuery.COLUMNS, sb.toString(), 1981b94bfa502569ce869d443353c174d02754d42a82Zheng Fu null, null, null, null); 1982b94bfa502569ce869d443353c174d02754d42a82Zheng Fu try { 1983b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while(cursor.moveToNext()) { 1984b94bfa502569ce869d443353c174d02754d42a82Zheng Fu foundIds.add(cursor.getLong(ContactIdQuery._ID)); 1985b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1986b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } finally { 1987b94bfa502569ce869d443353c174d02754d42a82Zheng Fu cursor.close(); 1988b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1989b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1990b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Exclude all contacts that did not match the filter 1991b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Iterator<MatchScore> iter = bestMatches.iterator(); 1992b94bfa502569ce869d443353c174d02754d42a82Zheng Fu while (iter.hasNext()) { 1993b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long id = iter.next().getContactId(); 1994b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (!foundIds.contains(id)) { 1995b94bfa502569ce869d443353c174d02754d42a82Zheng Fu iter.remove(); 1996b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1997b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 1998b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 1999b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Limit the number of returned suggestions 2000b94bfa502569ce869d443353c174d02754d42a82Zheng Fu final List<MatchScore> limitedMatches; 2001b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (bestMatches.size() > maxSuggestions) { 2002b94bfa502569ce869d443353c174d02754d42a82Zheng Fu limitedMatches = bestMatches.subList(0, maxSuggestions); 2003b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } else { 2004b94bfa502569ce869d443353c174d02754d42a82Zheng Fu limitedMatches = bestMatches; 2005b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 2006b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 2007b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Build an in-clause with the remaining contact IDs 2008b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.setLength(0); 2009b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.append(Contacts._ID); 2010b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.append(" IN ("); 2011b94bfa502569ce869d443353c174d02754d42a82Zheng Fu for (int i = 0; i < limitedMatches.size(); i++) { 2012b94bfa502569ce869d443353c174d02754d42a82Zheng Fu MatchScore matchScore = limitedMatches.get(i); 2013b94bfa502569ce869d443353c174d02754d42a82Zheng Fu if (i != 0) { 2014b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.append(","); 2015b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 2016b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.append(matchScore.getContactId()); 2017b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 2018b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sb.append(")"); 2019b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 2020b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Run the final query with the required projection and contact IDs found by the first query 2021b94bfa502569ce869d443353c174d02754d42a82Zheng Fu cursor = qb.query(db, projection, sb.toString(), null, null, null, Contacts._ID); 2022b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 2023b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Build a sorted list of discovered IDs 2024b94bfa502569ce869d443353c174d02754d42a82Zheng Fu ArrayList<Long> sortedContactIds = new ArrayList<Long>(limitedMatches.size()); 2025b94bfa502569ce869d443353c174d02754d42a82Zheng Fu for (MatchScore matchScore : limitedMatches) { 2026b94bfa502569ce869d443353c174d02754d42a82Zheng Fu sortedContactIds.add(matchScore.getContactId()); 2027b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 2028b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 2029b94bfa502569ce869d443353c174d02754d42a82Zheng Fu Collections.sort(sortedContactIds); 2030b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 2031b94bfa502569ce869d443353c174d02754d42a82Zheng Fu // Map cursor indexes according to the descending order of match scores 2032b94bfa502569ce869d443353c174d02754d42a82Zheng Fu int[] positionMap = new int[limitedMatches.size()]; 2033b94bfa502569ce869d443353c174d02754d42a82Zheng Fu for (int i = 0; i < positionMap.length; i++) { 2034b94bfa502569ce869d443353c174d02754d42a82Zheng Fu long id = limitedMatches.get(i).getContactId(); 2035b94bfa502569ce869d443353c174d02754d42a82Zheng Fu positionMap[i] = sortedContactIds.indexOf(id); 2036b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 2037b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 2038b94bfa502569ce869d443353c174d02754d42a82Zheng Fu return new ReorderingCursorWrapper(cursor, positionMap); 2039b94bfa502569ce869d443353c174d02754d42a82Zheng Fu } 2040b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 2041b94bfa502569ce869d443353c174d02754d42a82Zheng Fu /** 2042b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * Finds contacts with data matches and returns a list of {@link MatchScore}'s in the 2043b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * descending order of match score. 2044b94bfa502569ce869d443353c174d02754d42a82Zheng Fu * @param parameters 2045b94bfa502569ce869d443353c174d02754d42a82Zheng Fu */ 2046aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu protected abstract List<MatchScore> findMatchingContacts(final SQLiteDatabase db, 2047aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu long contactId, ArrayList<AggregationSuggestionParameter> parameters); 2048b94bfa502569ce869d443353c174d02754d42a82Zheng Fu 2049aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu public abstract void updateAggregationAfterVisibilityChange(long contactId); 2050b94bfa502569ce869d443353c174d02754d42a82Zheng Fu} 2051