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