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