ContactsProvider2.java revision f3f4a385d8d1d6788ba79ca353d02235de1d9b33
14f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/*
24f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Copyright (C) 2009 The Android Open Source Project
34f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton *
44f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License");
54f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * you may not use this file except in compliance with the License.
64f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * You may obtain a copy of the License at
74f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton *
84f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton *      http://www.apache.org/licenses/LICENSE-2.0
94f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton *
104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Unless required by applicable law or agreed to in writing, software
114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS,
124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * See the License for the specific language governing permissions and
144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * limitations under the License
154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */
164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarpackage com.android.providers.contacts;
1828f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar
193de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.internal.content.SyncStateContentProviderHelper;
203de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.ContactLookupKey.LookupKeySegment;
21b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregatedPresenceColumns;
22b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns;
23b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Clauses;
24b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns;
253296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkeyimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsStatusUpdatesColumns;
26b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns;
27b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns;
28b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns;
29b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns;
30b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType;
31b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NicknameLookupColumns;
32b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneColumns;
33b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns;
34b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns;
35b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns;
36b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SettingsColumns;
37b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns;
38b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Tables;
39a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikovimport com.google.android.collect.Lists;
40a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikovimport com.google.android.collect.Maps;
41a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikovimport com.google.android.collect.Sets;
423de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikov
43b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account;
44caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikovimport android.accounts.AccountManager;
455b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanaimport android.accounts.OnAccountsUpdateListener;
46c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager;
47568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderOperation;
48568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderResult;
496ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.content.ContentResolver;
5035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris;
5167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues;
5267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context;
53627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.IContentService;
54568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.OperationApplicationException;
553d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences;
56627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.SyncAdapterType;
5767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher;
583de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.content.SharedPreferences.Editor;
59b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.content.res.AssetFileDescriptor;
604cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Taoimport android.content.res.Configuration;
611129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikovimport android.database.CharArrayBuffer;
624f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor;
63ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.database.CursorWrapper;
64ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils;
65a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikovimport android.database.sqlite.SQLiteConstraintException;
66b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.database.sqlite.SQLiteContentHelper;
674f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase;
684f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder;
69c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millarimport android.database.sqlite.SQLiteStatement;
704f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri;
716ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.os.Bundle;
72d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport android.os.MemoryFile;
73b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException;
740e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport android.os.SystemProperties;
75d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport android.pim.vcard.VCardComposer;
767a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawaimport android.pim.vcard.VCardConfig;
773d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager;
78508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns;
793de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract;
803de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.LiveFolders;
813de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.OpenableColumns;
823de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.SyncStateContract;
83b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions;
84ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.provider.ContactsContract.ContactCounts;
853de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Contacts;
863de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Data;
875dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikovimport android.provider.ContactsContract.DisplayNameSources;
885dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikovimport android.provider.ContactsContract.FullNameStyle;
893de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Groups;
903de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.PhoneLookup;
915dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikovimport android.provider.ContactsContract.PhoneticNameStyle;
923de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
933de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Settings;
9482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikovimport android.provider.ContactsContract.StatusUpdates;
953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.BaseTypes;
96ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Email;
97ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im;
993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname;
1003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization;
101de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds.Phone;
102b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Photo;
1034097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
10467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
105a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils;
106a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils;
107f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikovimport android.text.util.Rfc822Token;
108f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikovimport android.text.util.Rfc822Tokenizer;
109c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log;
1104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
111d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.ByteArrayOutputStream;
112b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport java.io.FileNotFoundException;
113d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.IOException;
114d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.OutputStream;
115f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikovimport java.lang.ref.SoftReference;
1167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList;
117315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikovimport java.util.BitSet;
1185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.Collections;
119b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap;
1200e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.HashSet;
1214cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Taoimport java.util.Iterator;
1225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.List;
123622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkeyimport java.util.Locale;
124b5a4add17815167d20a90645779df34cdf45280dFred Quintanaimport java.util.Map;
1250e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.Set;
126ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch;
1274f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1284f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/**
1294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications
1304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}.
1314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */
1325b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanapublic class ContactsProvider2 extends SQLiteContentProvider implements OnAccountsUpdateListener {
133caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
134bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov    private static final String TAG = "ContactsProvider";
135bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov
136bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov    private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
1374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
138619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: carefully prevent all incoming nested queries; they can be gaping security holes
139619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: check for restricted flag during insert(), update(), and delete() calls
140619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
1413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Default for the maximum number of returned aggregation suggestions. */
1423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DEFAULT_MAX_SUGGESTIONS = 5;
1433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1443d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /**
1453d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * Shared preference key for the legacy contact import version. The need for a version
1463d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * as opposed to a boolean flag is that if we discover bugs in the contact import process,
1473d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * we can trigger re-import by incrementing the import version.
1483d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     */
1493d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private static final String PREF_CONTACTS_IMPORTED = "contacts_imported_v1";
1503d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private static final int PREF_CONTACTS_IMPORT_VERSION = 1;
1513d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1520e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff    private static final String AGGREGATE_CONTACTS = "sync.contacts.aggregate";
1530e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff
154a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
1554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1565e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar    private static final String TIMES_CONTACED_SORT_COLUMN = "times_contacted_sort";
1575e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar
158d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, "
1595e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar            + TIMES_CONTACED_SORT_COLUMN + " DESC, "
1609b43551f1ce33b79141772737a262ce609bd0cebMegha Joshi            + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
161d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar    private static final String STREQUENT_LIMIT =
162d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE "
163d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.STARRED + "=1) + 25";
164d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov
1656e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori    /* package */ static final String UPDATE_TIMES_CONTACTED_CONTACTS_TABLE =
1669b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            "UPDATE " + Tables.CONTACTS + " SET " + Contacts.TIMES_CONTACTED + "=" +
1679b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            " CASE WHEN " + Contacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " +
1689b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            " (" + Contacts.TIMES_CONTACTED + " + 1) END WHERE " + Contacts._ID + "=?";
1699b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori
1706e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori    /* package */ static final String UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE =
1719b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            "UPDATE " + Tables.RAW_CONTACTS + " SET " + RawContacts.TIMES_CONTACTED + "=" +
1729b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            " CASE WHEN " + RawContacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " +
1739b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            " (" + RawContacts.TIMES_CONTACTED + " + 1) END WHERE " + RawContacts.CONTACT_ID + "=?";
1749b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori
175d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS = 1000;
176d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS_ID = 1001;
1775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_LOOKUP = 1002;
1785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_LOOKUP_ID = 1003;
1795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_DATA = 1004;
1805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_FILTER = 1005;
1815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_STREQUENT = 1006;
1825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_STREQUENT_FILTER = 1007;
1835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_GROUP = 1008;
1845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_PHOTO = 1009;
185f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey    private static final int CONTACTS_AS_VCARD = 1010;
1864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1875ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS = 2002;
1885ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_ID = 2003;
1895ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_DATA = 2004;
19046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana    private static final int RAW_CONTACT_ENTITY_ID = 2005;
1914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1926bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA = 3000;
1936bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA_ID = 3001;
194ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int PHONES = 3002;
19548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int PHONES_ID = 3003;
19648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int PHONES_FILTER = 3004;
19748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS = 3005;
19848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS_ID = 3006;
19948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS_LOOKUP = 3007;
20048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS_FILTER = 3008;
20148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int POSTALS = 3009;
20248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int POSTALS_ID = 3010;
203a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2046bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int PHONE_LOOKUP = 4000;
2056bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
206b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTIONS = 6000;
207b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTION_ID = 6001;
208b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
20982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    private static final int STATUS_UPDATES = 7000;
21082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    private static final int STATUS_UPDATES_ID = 7001;
2111f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
21231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    private static final int AGGREGATION_SUGGESTIONS = 8000;
21331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
214eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    private static final int SETTINGS = 9000;
215eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
216ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS = 10000;
217ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_ID = 10001;
218ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_SUMMARY = 10003;
219ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
22035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana    private static final int SYNCSTATE = 11000;
221b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private static final int SYNCSTATE_ID = 11001;
22235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
223c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SUGGESTIONS = 12001;
224c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SHORTCUT = 12002;
225c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2261b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS = 14000;
2271b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_WITH_PHONES = 14001;
2281b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002;
2291b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003;
2301b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
23146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana    private static final int RAW_CONTACT_ENTITIES = 15001;
23246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
233d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private interface DataContactsQuery {
234f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov        public static final String TABLE = "data "
235f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                + "JOIN raw_contacts ON (data.raw_contact_id = raw_contacts._id) "
236f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                + "JOIN contacts ON (raw_contacts.contact_id = contacts._id)";
23767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
23867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
2396cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
2403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
241f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov            ContactsColumns.CONCRETE_ID
242ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
243ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
244d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
24567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA_ID = 1;
246d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int CONTACT_ID = 2;
247ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
2481f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
24914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    private interface DataDeleteQuery {
25067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
2513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
25288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] CONCRETE_COLUMNS = new String[] {
2533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
2543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
2555ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Data.RAW_CONTACT_ID,
2563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
257f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            Data.DATA1,
25888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        };
25988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov
26088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] COLUMNS = new String[] {
26188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data._ID,
26288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            MimetypesColumns.MIMETYPE,
26388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.RAW_CONTACT_ID,
26488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.IS_PRIMARY,
265f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            Data.DATA1,
2663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
2673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
26814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public static final int _ID = 0;
2693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 1;
2705ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 2;
2713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 3;
272f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        public static final int DATA1 = 4;
2733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
2743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
27514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    private interface DataUpdateQuery {
276321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        String[] COLUMNS = { Data._ID, Data.RAW_CONTACT_ID, Data.MIMETYPE };
27720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
27820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int _ID = 0;
279321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int RAW_CONTACT_ID = 1;
280321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int MIMETYPE = 2;
28120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
28220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
283f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
28419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka    private interface RawContactsQuery {
28519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        String TABLE = Tables.RAW_CONTACTS;
28619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka
28719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        String[] COLUMNS = new String[] {
288ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                RawContacts.DELETED,
289ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
290ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
29119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        };
29219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka
29319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        int DELETED = 0;
294ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        int ACCOUNT_TYPE = 1;
295ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        int ACCOUNT_NAME = 2;
29619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka    }
29719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka
298c76cdd0723b99f478c9ba5329d14a971cd8dfb3dCostin Manolache    public static final String DEFAULT_ACCOUNT_TYPE = "com.google";
299df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana    public static final String FEATURE_LEGACY_HOSTED_OR_GOOGLE = "legacy_hosted_or_google";
300caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
30171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov    /** Sql where statement for filtering on groups. */
30271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov    private static final String CONTACTS_IN_GROUP_SELECT =
30371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov            Contacts._ID + " IN "
30471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    + "(SELECT " + RawContacts.CONTACT_ID
30571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    + " FROM " + Tables.RAW_CONTACTS
30671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN "
30771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                            + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID
30871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                            + " FROM " + Tables.DATA_JOIN_MIMETYPES
30971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                            + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE
31071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + "' AND " + GroupMembership.GROUP_ROW_ID + "="
31171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + "(SELECT " + Tables.GROUPS + "." + Groups._ID
31271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + " FROM " + Tables.GROUPS
31371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + " WHERE " + Groups.TITLE + "=?)))";
31471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov
315a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    /** Sql for updating DIRTY flag on multiple raw contacts */
316a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    private static final String UPDATE_RAW_CONTACT_SET_DIRTY_SQL =
317a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            "UPDATE " + Tables.RAW_CONTACTS +
318a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            " SET " + RawContacts.DIRTY + "=1" +
319a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            " WHERE " + RawContacts._ID + " IN (";
320a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov
321a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    /** Sql for updating VERSION on multiple raw contacts */
322a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    private static final String UPDATE_RAW_CONTACT_SET_VERSION_SQL =
323a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            "UPDATE " + Tables.RAW_CONTACTS +
324a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            " SET " + RawContacts.VERSION + " = " + RawContacts.VERSION + " + 1" +
325a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            " WHERE " + RawContacts._ID + " IN (";
326a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov
327038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana    /** Contains just BaseColumns._COUNT */
328038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana    private static final HashMap<String, String> sCountProjectionMap;
329e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov    /** Contains just the contacts columns */
3304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    private static final HashMap<String, String> sContactsProjectionMap;
3315e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar    /** Used for pushing starred contacts to the top of a times contacted list **/
3325e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar    private static final HashMap<String, String> sStrequentStarredProjectionMap;
3335e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar    private static final HashMap<String, String> sStrequentFrequentProjectionMap;
334f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey    /** Contains just the contacts vCard columns */
335f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey    private static final HashMap<String, String> sContactsVCardProjectionMap;
336ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    /** Contains just the raw contacts columns */
337d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final HashMap<String, String> sRawContactsProjectionMap;
33846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana    /** Contains the columns from the raw contacts entity view*/
33946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana    private static final HashMap<String, String> sRawContactsEntityProjectionMap;
3404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /** Contains columns from the data view */
3414a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final HashMap<String, String> sDataProjectionMap;
3425e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    /** Contains columns from the data view */
3435e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    private static final HashMap<String, String> sDistinctDataProjectionMap;
3449261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /** Contains the data and contacts columns, for joined tables */
345e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov    private static final HashMap<String, String> sPhoneLookupProjectionMap;
346ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains the just the {@link Groups} columns */
347ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsProjectionMap;
348ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains {@link Groups} columns along with summary details */
349ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsSummaryProjectionMap;
350373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    /** Contains the agg_exceptions columns */
351b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final HashMap<String, String> sAggregationExceptionsProjectionMap;
352eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    /** Contains the agg_exceptions columns */
353eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    private static final HashMap<String, String> sSettingsProjectionMap;
35482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    /** Contains StatusUpdates columns */
35582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    private static final HashMap<String, String> sStatusUpdatesProjectionMap;
3561b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    /** Contains Live Folders columns */
3571b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final HashMap<String, String> sLiveFoldersProjectionMap;
3587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
3599705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    // where clause to update the status_updates table
3609705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    private static final String WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE =
3619705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdatesColumns.DATA_ID + " IN (SELECT Distinct " + StatusUpdates.DATA_ID +
3629705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            " FROM " + Tables.STATUS_UPDATES + " LEFT OUTER JOIN " + Tables.PRESENCE +
3639705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            " ON " + StatusUpdatesColumns.DATA_ID + " = " + StatusUpdates.DATA_ID + " WHERE ";
3649705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
365c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Precompiled sql statement for setting a data record to the primary. */
366c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetPrimaryStatement;
3673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for setting a data record to the super primary. */
368c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetSuperPrimaryStatement;
3693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for updating a contact display name */
37025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov    private SQLiteStatement mRawContactDisplayNameUpdate;
37182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    /** Precompiled sql statement for updating an aggregated status update */
372a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov    private SQLiteStatement mLastStatusUpdate;
373f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private SQLiteStatement mNameLookupInsert;
374f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private SQLiteStatement mNameLookupDelete;
375a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov    private SQLiteStatement mStatusUpdateAutoTimestamp;
376a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov    private SQLiteStatement mStatusUpdateInsert;
377a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov    private SQLiteStatement mStatusUpdateReplace;
3780a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov    private SQLiteStatement mStatusAttributionUpdate;
379a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov    private SQLiteStatement mStatusUpdateDelete;
380f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov    private SQLiteStatement mResetNameVerifiedForOtherRawContacts;
381a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
382f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov    private long mMimeTypeIdEmail;
383f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov    private long mMimeTypeIdIm;
3841129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private long mMimeTypeIdStructuredName;
3851129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private long mMimeTypeIdOrganization;
3861129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private long mMimeTypeIdNickname;
3871129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private long mMimeTypeIdPhone;
388f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov    private StringBuilder mSb = new StringBuilder();
3891129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private String[] mSelectionArgs1 = new String[1];
3901129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private String[] mSelectionArgs2 = new String[2];
3911129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private String[] mSelectionArgs3 = new String[3];
392f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    private Account mAccount;
393f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov
3944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    static {
3954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        // Contacts URI matching table
396a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final UriMatcher matcher = sUriMatcher;
397d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS);
398d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
399d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_DATA);
4003653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions",
4013653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                AGGREGATION_SUGGESTIONS);
4022d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*",
4032d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                AGGREGATION_SUGGESTIONS);
4043653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_PHOTO);
4055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER);
4065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP);
4075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID);
408f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD);
4095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT);
410ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*",
411ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                CONTACTS_STREQUENT_FILTER);
4125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP);
4133653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
4145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
4155ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID);
4165ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA);
41746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ENTITY_ID);
41846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
41946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES);
420b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
4214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);
4224f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID);
423ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES);
42448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID);
4255e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER);
426ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER);
4274a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS);
42848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID);
4295e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP);
4305e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER);
4314a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER);
432ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS);
43348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID);
4341f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
435ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS);
436ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID);
437ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY);
438ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
43935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE);
440b5a4add17815167d20a90645779df34cdf45280dFred Quintana        matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#",
441b5a4add17815167d20a90645779df34cdf45280dFred Quintana                SYNCSTATE_ID);
44235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
443a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP);
444b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions",
445b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTIONS);
446b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*",
447b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTION_ID);
4484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
449eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS);
450eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
45182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES);
45282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID);
4531f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
454c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
455c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
456c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
457c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
4582d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*",
459c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SHORTCUT);
460c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
4611b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts",
4621b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS);
4631b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*",
4641b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_GROUP_NAME);
4651b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones",
4661b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_WITH_PHONES);
4671b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites",
4681b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_FAVORITES);
46919a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov    }
47019a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
47119a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov    static {
472038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        sCountProjectionMap = new HashMap<String, String>();
473038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        sCountProjectionMap.put(BaseColumns._COUNT, "COUNT(*)");
474e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
4754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap = new HashMap<String, String>();
4764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts._ID, Contacts._ID);
4775dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME_PRIMARY);
4785dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.DISPLAY_NAME_ALTERNATIVE,
4795dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                Contacts.DISPLAY_NAME_ALTERNATIVE);
4805dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.DISPLAY_NAME_SOURCE, Contacts.DISPLAY_NAME_SOURCE);
4815dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.PHONETIC_NAME, Contacts.PHONETIC_NAME);
4825dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.PHONETIC_NAME_STYLE, Contacts.PHONETIC_NAME_STYLE);
4835dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.SORT_KEY_PRIMARY, Contacts.SORT_KEY_PRIMARY);
4845dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.SORT_KEY_ALTERNATIVE, Contacts.SORT_KEY_ALTERNATIVE);
4854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
4864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
4874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
4884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.IN_VISIBLE_GROUP, Contacts.IN_VISIBLE_GROUP);
4894a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
4904a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
491f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov        sContactsProjectionMap.put(Contacts.HAS_PHONE_NUMBER, Contacts.HAS_PHONE_NUMBER);
4924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
4935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sContactsProjectionMap.put(Contacts.LOOKUP_KEY, Contacts.LOOKUP_KEY);
494f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey
4953296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        // Handle projections for Contacts-level statuses
4963296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sContactsProjectionMap, Contacts.CONTACT_PRESENCE,
4973296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE);
4983296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sContactsProjectionMap, Contacts.CONTACT_STATUS,
4993296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS);
5003296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sContactsProjectionMap, Contacts.CONTACT_STATUS_TIMESTAMP,
5013296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP);
5023296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sContactsProjectionMap, Contacts.CONTACT_STATUS_RES_PACKAGE,
5033296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE);
5043296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sContactsProjectionMap, Contacts.CONTACT_STATUS_LABEL,
5053296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL);
5063296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sContactsProjectionMap, Contacts.CONTACT_STATUS_ICON,
5073296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON);
5083296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey
5095e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        sStrequentStarredProjectionMap = new HashMap<String, String>(sContactsProjectionMap);
5105e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        sStrequentStarredProjectionMap.put(TIMES_CONTACED_SORT_COLUMN,
5115e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                  Long.MAX_VALUE + " AS " + TIMES_CONTACED_SORT_COLUMN);
5125e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar
5135e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        sStrequentFrequentProjectionMap = new HashMap<String, String>(sContactsProjectionMap);
5145e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        sStrequentFrequentProjectionMap.put(TIMES_CONTACED_SORT_COLUMN,
5155e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                  Contacts.TIMES_CONTACTED + " AS " + TIMES_CONTACED_SORT_COLUMN);
5165e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar
517f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey        sContactsVCardProjectionMap = Maps.newHashMap();
518f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey        sContactsVCardProjectionMap.put(OpenableColumns.DISPLAY_NAME, Contacts.DISPLAY_NAME
519d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                + " || '.vcf' AS " + OpenableColumns.DISPLAY_NAME);
520ba355248c255551bc65d8023b968513cbe9bcdf3Jeff Sharkey        sContactsVCardProjectionMap.put(OpenableColumns.SIZE, "NULL AS " + OpenableColumns.SIZE);
5214a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
5224a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap = new HashMap<String, String>();
5234a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts._ID, RawContacts._ID);
5244a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
5254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
5264a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
5274a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
5284a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.VERSION, RawContacts.VERSION);
5294a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DIRTY, RawContacts.DIRTY);
5304a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DELETED, RawContacts.DELETED);
5315dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DISPLAY_NAME_PRIMARY,
5325dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                RawContacts.DISPLAY_NAME_PRIMARY);
5335dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DISPLAY_NAME_ALTERNATIVE,
5345dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                RawContacts.DISPLAY_NAME_ALTERNATIVE);
5355dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DISPLAY_NAME_SOURCE,
5365dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                RawContacts.DISPLAY_NAME_SOURCE);
5375dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.PHONETIC_NAME,
5385dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                RawContacts.PHONETIC_NAME);
5395dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.PHONETIC_NAME_STYLE,
5405dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                RawContacts.PHONETIC_NAME_STYLE);
541f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.NAME_VERIFIED,
542f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                RawContacts.NAME_VERIFIED);
5435dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SORT_KEY_PRIMARY,
5445dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                RawContacts.SORT_KEY_PRIMARY);
5455dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SORT_KEY_ALTERNATIVE,
5465dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                RawContacts.SORT_KEY_ALTERNATIVE);
5474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.TIMES_CONTACTED, RawContacts.TIMES_CONTACTED);
5484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.LAST_TIME_CONTACTED,
5494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                RawContacts.LAST_TIME_CONTACTED);
5504a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.CUSTOM_RINGTONE, RawContacts.CUSTOM_RINGTONE);
5514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SEND_TO_VOICEMAIL, RawContacts.SEND_TO_VOICEMAIL);
5524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.STARRED, RawContacts.STARRED);
5534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE);
5544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC1, RawContacts.SYNC1);
5554a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC2, RawContacts.SYNC2);
5564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC3, RawContacts.SYNC3);
5574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC4, RawContacts.SYNC4);
5582815f58f72f109790585931f601a63ddc02536a5Evan Millar
5594a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap = new HashMap<String, String>();
5604a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data._ID, Data._ID);
5614a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.RAW_CONTACT_ID, Data.RAW_CONTACT_ID);
5624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA_VERSION, Data.DATA_VERSION);
5634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.IS_PRIMARY, Data.IS_PRIMARY);
5644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY);
5654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.RES_PACKAGE, Data.RES_PACKAGE);
5664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.MIMETYPE, Data.MIMETYPE);
5674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA1, Data.DATA1);
5684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA2, Data.DATA2);
5694a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA3, Data.DATA3);
5704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA4, Data.DATA4);
5714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA5, Data.DATA5);
5724a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA6, Data.DATA6);
5734a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA7, Data.DATA7);
5744a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA8, Data.DATA8);
5754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA9, Data.DATA9);
5764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA10, Data.DATA10);
5774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA11, Data.DATA11);
5784a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA12, Data.DATA12);
5794a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA13, Data.DATA13);
5804a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA14, Data.DATA14);
5814a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA15, Data.DATA15);
5824a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC1, Data.SYNC1);
5834a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC2, Data.SYNC2);
5844a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC3, Data.SYNC3);
5854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC4, Data.SYNC4);
58682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sDataProjectionMap.put(Data.CONTACT_ID, Data.CONTACT_ID);
5874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
5884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
5894a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
5904a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.VERSION, RawContacts.VERSION);
5914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.DIRTY, RawContacts.DIRTY);
592f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.NAME_VERIFIED, RawContacts.NAME_VERIFIED);
59356d2bd40ebb238c2990bc239f68c7e61c7d5b02cEvan Millar        sDataProjectionMap.put(Contacts.LOOKUP_KEY, Contacts.LOOKUP_KEY);
5944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME);
5955dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDataProjectionMap.put(Contacts.DISPLAY_NAME_ALTERNATIVE,
5965dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                Contacts.DISPLAY_NAME_ALTERNATIVE);
5975dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDataProjectionMap.put(Contacts.DISPLAY_NAME_SOURCE, Contacts.DISPLAY_NAME_SOURCE);
5985dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDataProjectionMap.put(Contacts.PHONETIC_NAME, Contacts.PHONETIC_NAME);
5995dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDataProjectionMap.put(Contacts.PHONETIC_NAME_STYLE, Contacts.PHONETIC_NAME_STYLE);
6005dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDataProjectionMap.put(Contacts.SORT_KEY_PRIMARY, Contacts.SORT_KEY_PRIMARY);
6015dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDataProjectionMap.put(Contacts.SORT_KEY_ALTERNATIVE, Contacts.SORT_KEY_ALTERNATIVE);
6024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
6034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
6044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
6054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
6064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
6074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
608a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov        sDataProjectionMap.put(Contacts.IN_VISIBLE_GROUP, Contacts.IN_VISIBLE_GROUP);
6094a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(GroupMembership.GROUP_SOURCE_ID, GroupMembership.GROUP_SOURCE_ID);
610a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
61146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        HashMap<String, String> columns;
61246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns = new HashMap<String, String>();
61346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts._ID, RawContacts._ID);
61446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
61546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
61646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
61746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
61846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.VERSION, RawContacts.VERSION);
61946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.DIRTY, RawContacts.DIRTY);
62046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.DELETED, RawContacts.DELETED);
621bf6a7e4dece49ba4e7cda17f7ed9250aeb82f731Jeff Sharkey        columns.put(RawContacts.IS_RESTRICTED, RawContacts.IS_RESTRICTED);
62246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.SYNC1, RawContacts.SYNC1);
62346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.SYNC2, RawContacts.SYNC2);
62446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.SYNC3, RawContacts.SYNC3);
62546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.SYNC4, RawContacts.SYNC4);
626f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov        columns.put(RawContacts.NAME_VERIFIED, RawContacts.NAME_VERIFIED);
62746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.RES_PACKAGE, Data.RES_PACKAGE);
62846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.MIMETYPE, Data.MIMETYPE);
62946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA1, Data.DATA1);
63046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA2, Data.DATA2);
63146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA3, Data.DATA3);
63246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA4, Data.DATA4);
63346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA5, Data.DATA5);
63446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA6, Data.DATA6);
63546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA7, Data.DATA7);
63646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA8, Data.DATA8);
63746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA9, Data.DATA9);
63846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA10, Data.DATA10);
63946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA11, Data.DATA11);
64046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA12, Data.DATA12);
64146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA13, Data.DATA13);
64246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA14, Data.DATA14);
64346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA15, Data.DATA15);
64446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.SYNC1, Data.SYNC1);
64546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.SYNC2, Data.SYNC2);
64646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.SYNC3, Data.SYNC3);
64746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.SYNC4, Data.SYNC4);
64846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(RawContacts.Entity.DATA_ID, RawContacts.Entity.DATA_ID);
64946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.STARRED, Data.STARRED);
65046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.DATA_VERSION, Data.DATA_VERSION);
65146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.IS_PRIMARY, Data.IS_PRIMARY);
65246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY);
65346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        columns.put(GroupMembership.GROUP_SOURCE_ID, GroupMembership.GROUP_SOURCE_ID);
65446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        sRawContactsEntityProjectionMap = columns;
65546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
6563296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        // Handle projections for Contacts-level statuses
6573296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Contacts.CONTACT_PRESENCE,
6583296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE);
6593296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Contacts.CONTACT_STATUS,
6603296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS);
6613296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Contacts.CONTACT_STATUS_TIMESTAMP,
6623296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP);
6633296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Contacts.CONTACT_STATUS_RES_PACKAGE,
6643296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE);
6653296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Contacts.CONTACT_STATUS_LABEL,
6663296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL);
6673296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Contacts.CONTACT_STATUS_ICON,
6683296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON);
6693296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey
6703296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        // Handle projections for Data-level statuses
6713296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Data.PRESENCE,
6723296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                Tables.PRESENCE + "." + StatusUpdates.PRESENCE);
6733296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Data.STATUS,
6743296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                StatusUpdatesColumns.CONCRETE_STATUS);
6753296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Data.STATUS_TIMESTAMP,
6763296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                StatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP);
6773296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Data.STATUS_RES_PACKAGE,
6783296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                StatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE);
6793296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Data.STATUS_LABEL,
6803296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                StatusUpdatesColumns.CONCRETE_STATUS_LABEL);
6813296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDataProjectionMap, Data.STATUS_ICON,
6823296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                StatusUpdatesColumns.CONCRETE_STATUS_ICON);
6833296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey
6845e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        // Projection map for data grouped by contact (not raw contact) and some data field(s)
6855e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap = new HashMap<String, String>();
6865e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data._ID,
6875e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                "MIN(" + Data._ID + ") AS " + Data._ID);
6885e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA_VERSION, Data.DATA_VERSION);
6895e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.IS_PRIMARY, Data.IS_PRIMARY);
6905e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY);
6915e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.RES_PACKAGE, Data.RES_PACKAGE);
6925e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.MIMETYPE, Data.MIMETYPE);
6935e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA1, Data.DATA1);
6945e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA2, Data.DATA2);
6955e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA3, Data.DATA3);
6965e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA4, Data.DATA4);
6975e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA5, Data.DATA5);
6985e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA6, Data.DATA6);
6995e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA7, Data.DATA7);
7005e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA8, Data.DATA8);
7015e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA9, Data.DATA9);
7025e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA10, Data.DATA10);
7035e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA11, Data.DATA11);
7045e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA12, Data.DATA12);
7055e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA13, Data.DATA13);
7065e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA14, Data.DATA14);
7075e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA15, Data.DATA15);
7085e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.SYNC1, Data.SYNC1);
7095e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.SYNC2, Data.SYNC2);
7105e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.SYNC3, Data.SYNC3);
7115e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.SYNC4, Data.SYNC4);
7125e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
7138f1631f8a610e7278526916ce73ac1e422a5c9b8Jeff Sharkey        sDistinctDataProjectionMap.put(Contacts.LOOKUP_KEY, Contacts.LOOKUP_KEY);
7145e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME);
7155dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.DISPLAY_NAME_ALTERNATIVE,
7165dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                Contacts.DISPLAY_NAME_ALTERNATIVE);
7175dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.DISPLAY_NAME_SOURCE, Contacts.DISPLAY_NAME_SOURCE);
7185dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.PHONETIC_NAME, Contacts.PHONETIC_NAME);
7195dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.PHONETIC_NAME_STYLE, Contacts.PHONETIC_NAME_STYLE);
7205dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.SORT_KEY_PRIMARY, Contacts.SORT_KEY_PRIMARY);
7215dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.SORT_KEY_ALTERNATIVE,
7225dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                Contacts.SORT_KEY_ALTERNATIVE);
7235e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
7245e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
7255e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
7265e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
7275e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
7285e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
729a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.IN_VISIBLE_GROUP, Contacts.IN_VISIBLE_GROUP);
7305e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(GroupMembership.GROUP_SOURCE_ID,
7315e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                GroupMembership.GROUP_SOURCE_ID);
7325e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
7333296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        // Handle projections for Contacts-level statuses
7343296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Contacts.CONTACT_PRESENCE,
7353296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE);
7363296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Contacts.CONTACT_STATUS,
7373296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS);
7383296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Contacts.CONTACT_STATUS_TIMESTAMP,
7393296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP);
7403296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Contacts.CONTACT_STATUS_RES_PACKAGE,
7413296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE);
7423296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Contacts.CONTACT_STATUS_LABEL,
7433296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL);
7443296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Contacts.CONTACT_STATUS_ICON,
7453296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON);
7463296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey
7473296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        // Handle projections for Data-level statuses
7483296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Data.PRESENCE,
7493296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                Tables.PRESENCE + "." + StatusUpdates.PRESENCE);
7503296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Data.STATUS,
7513296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                StatusUpdatesColumns.CONCRETE_STATUS);
7523296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Data.STATUS_TIMESTAMP,
7533296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                StatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP);
7543296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Data.STATUS_RES_PACKAGE,
7553296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                StatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE);
7563296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Data.STATUS_LABEL,
7573296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                StatusUpdatesColumns.CONCRETE_STATUS_LABEL);
7583296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        addProjection(sDistinctDataProjectionMap, Data.STATUS_ICON,
7593296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                StatusUpdatesColumns.CONCRETE_STATUS_ICON);
7603296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey
761e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap = new HashMap<String, String>();
762e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup._ID,
763fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                "contacts_view." + Contacts._ID
764fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        + " AS " + PhoneLookup._ID);
76556d2bd40ebb238c2990bc239f68c7e61c7d5b02cEvan Millar        sPhoneLookupProjectionMap.put(PhoneLookup.LOOKUP_KEY,
766fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                "contacts_view." + Contacts.LOOKUP_KEY
767fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        + " AS " + PhoneLookup.LOOKUP_KEY);
768e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.DISPLAY_NAME,
769fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                "contacts_view." + Contacts.DISPLAY_NAME
770fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        + " AS " + PhoneLookup.DISPLAY_NAME);
771e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.LAST_TIME_CONTACTED,
772fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                "contacts_view." + Contacts.LAST_TIME_CONTACTED
773e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                        + " AS " + PhoneLookup.LAST_TIME_CONTACTED);
774e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.TIMES_CONTACTED,
775fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                "contacts_view." + Contacts.TIMES_CONTACTED
776fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        + " AS " + PhoneLookup.TIMES_CONTACTED);
777e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.STARRED,
778fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                "contacts_view." + Contacts.STARRED
779fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        + " AS " + PhoneLookup.STARRED);
780e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.IN_VISIBLE_GROUP,
781fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                "contacts_view." + Contacts.IN_VISIBLE_GROUP
782fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        + " AS " + PhoneLookup.IN_VISIBLE_GROUP);
783e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.PHOTO_ID,
784fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                "contacts_view." + Contacts.PHOTO_ID
785fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        + " AS " + PhoneLookup.PHOTO_ID);
786e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.CUSTOM_RINGTONE,
787fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                "contacts_view." + Contacts.CUSTOM_RINGTONE
788fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        + " AS " + PhoneLookup.CUSTOM_RINGTONE);
789e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.HAS_PHONE_NUMBER,
790fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                "contacts_view." + Contacts.HAS_PHONE_NUMBER
791fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        + " AS " + PhoneLookup.HAS_PHONE_NUMBER);
792e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.SEND_TO_VOICEMAIL,
793fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                "contacts_view." + Contacts.SEND_TO_VOICEMAIL
794e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                        + " AS " + PhoneLookup.SEND_TO_VOICEMAIL);
795e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.NUMBER,
796e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.NUMBER + " AS " + PhoneLookup.NUMBER);
797e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.TYPE,
798e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.TYPE + " AS " + PhoneLookup.TYPE);
799e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.LABEL,
800e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.LABEL + " AS " + PhoneLookup.LABEL);
8019261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
802ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Groups projection map
803ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
80489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups._ID, Groups._ID);
805035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_NAME, Groups.ACCOUNT_NAME);
806035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_TYPE, Groups.ACCOUNT_TYPE);
8079261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.SOURCE_ID, Groups.SOURCE_ID);
8089261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.DIRTY, Groups.DIRTY);
8099261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.VERSION, Groups.VERSION);
81089c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups.RES_PACKAGE, Groups.RES_PACKAGE);
811ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.TITLE, Groups.TITLE);
81267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Groups.TITLE_RES, Groups.TITLE_RES);
813ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.GROUP_VISIBLE, Groups.GROUP_VISIBLE);
8143cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYSTEM_ID, Groups.SYSTEM_ID);
81594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        columns.put(Groups.DELETED, Groups.DELETED);
8163cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.NOTES, Groups.NOTES);
81738446bf47c5ee2080df69f5fc8a33ad2fa3e61b5Jeff Sharkey        columns.put(Groups.SHOULD_SYNC, Groups.SHOULD_SYNC);
81889c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups.SYNC1, Groups.SYNC1);
81989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups.SYNC2, Groups.SYNC2);
82089c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups.SYNC3, Groups.SYNC3);
82189c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups.SYNC4, Groups.SYNC4);
822ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsProjectionMap = columns;
823ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
8246cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        // RawContacts and groups projection map
825ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
826ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.putAll(sGroupsProjectionMap);
827d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Groups.SUMMARY_COUNT, "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID
828d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
829ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
830ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + ") AS " + Groups.SUMMARY_COUNT);
831ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.SUMMARY_WITH_PHONES, "(SELECT COUNT(DISTINCT "
832d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ContactsColumns.CONCRETE_ID + ") FROM "
833d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
834ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
835f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov                + " AND " + Contacts.HAS_PHONE_NUMBER + ") AS " + Groups.SUMMARY_WITH_PHONES);
836ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsSummaryProjectionMap = columns;
837ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
838b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        // Aggregate exception projection map
839b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns = new HashMap<String, String>();
840b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id AS _id");
841b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE);
8420c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        columns.put(AggregationExceptions.RAW_CONTACT_ID1, AggregationExceptions.RAW_CONTACT_ID1);
8430c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        columns.put(AggregationExceptions.RAW_CONTACT_ID2, AggregationExceptions.RAW_CONTACT_ID2);
844b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        sAggregationExceptionsProjectionMap = columns;
845b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
846eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        // Settings projection map
847eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns = new HashMap<String, String>();
848eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.ACCOUNT_NAME, Settings.ACCOUNT_NAME);
849eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.ACCOUNT_TYPE, Settings.ACCOUNT_TYPE);
850eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.UNGROUPED_VISIBLE, Settings.UNGROUPED_VISIBLE);
851eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.SHOULD_SYNC, Settings.SHOULD_SYNC);
852341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey        columns.put(Settings.ANY_UNSYNCED, "(CASE WHEN MIN(" + Settings.SHOULD_SYNC
853341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey                + ",(SELECT (CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL THEN 1 ELSE MIN("
854341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey                + Groups.SHOULD_SYNC + ") END) FROM " + Tables.GROUPS + " WHERE "
855fc4e892529eccdfa42121f0304ec7d0dbb42d6c9Dmitri Plotnikov                + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" + SettingsColumns.CONCRETE_ACCOUNT_NAME
856341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey                + " AND " + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "="
857341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey                + SettingsColumns.CONCRETE_ACCOUNT_TYPE + "))=0 THEN 1 ELSE 0 END) AS "
858341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey                + Settings.ANY_UNSYNCED);
85968936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey        columns.put(Settings.UNGROUPED_COUNT, "(SELECT COUNT(*) FROM (SELECT 1 FROM "
86068936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS + " GROUP BY "
86168936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID + " HAVING " + Clauses.HAVING_NO_GROUPS
86268936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + ")) AS " + Settings.UNGROUPED_COUNT);
86368936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey        columns.put(Settings.UNGROUPED_WITH_PHONES, "(SELECT COUNT(*) FROM (SELECT 1 FROM "
864e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS + " WHERE "
86568936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Contacts.HAS_PHONE_NUMBER + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID
86668936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + " HAVING " + Clauses.HAVING_NO_GROUPS + ")) AS "
86768936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Settings.UNGROUPED_WITH_PHONES);
868eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        sSettingsProjectionMap = columns;
869eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
870373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns = new HashMap<String, String>();
8714dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        columns.put(PresenceColumns.RAW_CONTACT_ID, PresenceColumns.RAW_CONTACT_ID);
8720a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        columns.put(StatusUpdates.DATA_ID,
8730a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                DataColumns.CONCRETE_ID + " AS " + StatusUpdates.DATA_ID);
87482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.IM_ACCOUNT, StatusUpdates.IM_ACCOUNT);
87582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.IM_HANDLE, StatusUpdates.IM_HANDLE);
87682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.PROTOCOL, StatusUpdates.PROTOCOL);
87770c314fb9b2ef3d47340b93816d46200aba9f5ecDmitri Plotnikov        // We cannot allow a null in the custom protocol field, because SQLite3 does not
87870c314fb9b2ef3d47340b93816d46200aba9f5ecDmitri Plotnikov        // properly enforce uniqueness of null values
87982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.CUSTOM_PROTOCOL, "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL
88082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                + "='' THEN NULL ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END) AS "
88182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                + StatusUpdates.CUSTOM_PROTOCOL);
88282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.PRESENCE, StatusUpdates.PRESENCE);
8830a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        columns.put(StatusUpdates.STATUS, StatusUpdates.STATUS);
8840a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        columns.put(StatusUpdates.STATUS_TIMESTAMP, StatusUpdates.STATUS_TIMESTAMP);
8850a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        columns.put(StatusUpdates.STATUS_RES_PACKAGE, StatusUpdates.STATUS_RES_PACKAGE);
8860a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        columns.put(StatusUpdates.STATUS_ICON, StatusUpdates.STATUS_ICON);
8870a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        columns.put(StatusUpdates.STATUS_LABEL, StatusUpdates.STATUS_LABEL);
88882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sStatusUpdatesProjectionMap = columns;
88919a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
8901b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // Live folder projection
8911b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap = new HashMap<String, String>();
8921b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap.put(LiveFolders._ID,
8931b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                Contacts._ID + " AS " + LiveFolders._ID);
8941b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap.put(LiveFolders.NAME,
8951b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                Contacts.DISPLAY_NAME + " AS " + LiveFolders.NAME);
8961b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // TODO: Put contact photo back when we have a way to display a default icon
8971b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // for contacts without a photo
8981b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // sLiveFoldersProjectionMap.put(LiveFolders.ICON_BITMAP,
8991b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        //      Photos.DATA + " AS " + LiveFolders.ICON_BITMAP);
9004f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
9014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
9023296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey    private static void addProjection(HashMap<String, String> map, String toField, String fromField) {
9033296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        map.put(toField, fromField + " AS " + toField);
9043296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey    }
9053296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey
9063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /**
9073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     * Handles inserts and update for a specific Data type.
9083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     */
9093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private abstract class DataRowHandler {
9103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected final String mMimetype;
912653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        protected long mMimetypeId;
9133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9141129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        @SuppressWarnings("all")
9153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public DataRowHandler(String mimetype) {
9163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mMimetype = mimetype;
917a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka
918a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            // To ensure the data column position. This is dead code if properly configured.
919a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            if (StructuredName.DISPLAY_NAME != Data.DATA1 || Nickname.NAME != Data.DATA1
920a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    || Organization.COMPANY != Data.DATA1 || Phone.NUMBER != Data.DATA1
921a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    || Email.DATA != Data.DATA1) {
922a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                throw new AssertionError("Some of ContactsContract.CommonDataKinds class primary"
923a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                        + " data is not in DATA1 column");
924a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            }
9253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
927653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        protected long getMimeTypeId() {
928653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (mMimetypeId == 0) {
929b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                mMimetypeId = mDbHelper.getMimeTypeId(mMimetype);
930653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
931653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return mMimetypeId;
932653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
933653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
9343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
9353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Inserts a row into the {@link Data} table.
9363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
9375ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
938e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            final long dataId = db.insert(Tables.DATA, null, values);
939e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
940e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            Integer primary = values.getAsInteger(Data.IS_PRIMARY);
941e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (primary != null && primary != 0) {
942653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, getMimeTypeId());
943e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
944e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
945e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return dataId;
9463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
9493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Validates data and updates a {@link Data} row using the cursor, which contains
9503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * the current data.
9513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
952653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
953f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
95414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
95514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
956653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
957653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (values.containsKey(Data.IS_SUPER_PRIMARY)) {
958653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                long mimeTypeId = getMimeTypeId();
959653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
960653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, mimeTypeId);
961653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
962653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                // Now that we've taken care of setting these, remove them from "values".
963653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_SUPER_PRIMARY);
964653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_PRIMARY);
965653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            } else if (values.containsKey(Data.IS_PRIMARY)) {
966653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, getMimeTypeId());
967653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
968653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                // Now that we've taken care of setting this, remove it from "values".
969653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_PRIMARY);
970653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
971653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
972653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (values.size() > 0) {
9734da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                mSelectionArgs1[0] = String.valueOf(dataId);
9744da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                mDb.update(Tables.DATA, values, Data._ID + " =?", mSelectionArgs1);
975653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
976653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
977f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            if (!callerIsSyncAdapter) {
978653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setRawContactDirty(rawContactId);
979653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
9803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
98314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
98414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
98514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            boolean primary = c.getInt(DataDeleteQuery.IS_PRIMARY) != 0;
9864da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(dataId);
9874da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            int count = db.delete(Tables.DATA, Data._ID + "=?", mSelectionArgs1);
9884da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(rawContactId);
9894da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            db.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=?", mSelectionArgs1);
9903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (count != 0 && primary) {
9915ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                fixPrimary(db, rawContactId);
9923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return count;
9943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9965ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        private void fixPrimary(SQLiteDatabase db, long rawContactId) {
9974da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            long mimeTypeId = getMimeTypeId();
998e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            long primaryId = -1;
999e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            int primaryType = -1;
10004da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(rawContactId);
10014da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            Cursor c = db.query(DataDeleteQuery.TABLE,
10024da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    DataDeleteQuery.CONCRETE_COLUMNS,
10034da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    Data.RAW_CONTACT_ID + "=?" +
10044da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        " AND " + DataColumns.MIMETYPE_ID + "=" + mimeTypeId,
10054da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    mSelectionArgs1, null, null, null);
10063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
1007e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                while (c.moveToNext()) {
100814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    long dataId = c.getLong(DataDeleteQuery._ID);
1009f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                    int type = c.getInt(DataDeleteQuery.DATA1);
1010e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) {
1011e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryId = dataId;
1012e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryType = type;
1013e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    }
10143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
10153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
10163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
10173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
10184da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            if (primaryId != -1) {
10194da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                setIsPrimary(rawContactId, primaryId, mimeTypeId);
10204da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            }
1021e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1022e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1023e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        /**
1024e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * Returns the rank of a specific record type to be used in determining the primary
1025e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * row. Lower number represents higher priority.
1026e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         */
1027e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
1028e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return 0;
10293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
10303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
103125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        protected void fixRawContactDisplayName(SQLiteDatabase db, long rawContactId) {
1032285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            if (!isNewRawContact(rawContactId)) {
1033d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov                updateRawContactDisplayName(db, rawContactId);
1034fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                mContactAggregator.updateDisplayNameForRawContact(db, rawContactId);
1035285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
10363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
1037a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1038a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
1039a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return true;
1040a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1041622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1042622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1043622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Return set of values, using current values at given {@link Data#_ID}
1044622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * as baseline, but augmented with any updates.
1045622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1046622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public ContentValues getAugmentedValues(SQLiteDatabase db, long dataId,
1047622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                ContentValues update) {
1048622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues values = new ContentValues();
10494da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(dataId);
10504da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            final Cursor cursor = db.query(Tables.DATA, null, Data._ID + "=?",
10514da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    mSelectionArgs1, null, null, null);
1052622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            try {
1053622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                if (cursor.moveToFirst()) {
1054622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                    for (int i = 0; i < cursor.getColumnCount(); i++) {
1055622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                        final String key = cursor.getColumnName(i);
1056622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                        values.put(key, cursor.getString(i));
1057622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                    }
1058622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                }
1059622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            } finally {
1060622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                cursor.close();
1061622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
1062622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            values.putAll(update);
1063622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            return values;
1064622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
10653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
10663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CustomDataRowHandler extends DataRowHandler {
10683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CustomDataRowHandler(String mimetype) {
10703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
10713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
10723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
10733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class StructuredNameRowHandler extends DataRowHandler {
1075622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private final NameSplitter mSplitter;
10763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1077622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public StructuredNameRowHandler(NameSplitter splitter) {
10783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(StructuredName.CONTENT_ITEM_TYPE);
1079622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            mSplitter = splitter;
10803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
10813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
10835ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1084622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredNameComponents(values, values);
108514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
108614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
108714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1088f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            String name = values.getAsString(StructuredName.DISPLAY_NAME);
1089f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            insertNameLookupForStructuredName(rawContactId, dataId, name);
109025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
109114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
109214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
109314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
109414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
109514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1096f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
1097622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long dataId = c.getLong(DataUpdateQuery._ID);
1098622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1099cabac02a2416b495e030654accffcbb5ae526678Dmitri Plotnikov
1100622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues augmented = getAugmentedValues(db, dataId, values);
1101622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredNameComponents(augmented, values);
110214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1103f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
110414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1105f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            if (values.containsKey(StructuredName.DISPLAY_NAME)) {
1106f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                String name = values.getAsString(StructuredName.DISPLAY_NAME);
1107f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                deleteNameLookup(dataId);
1108f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                insertNameLookupForStructuredName(rawContactId, dataId, name);
110914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            }
111025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
111114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
111214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
111314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
111414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
111514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
111614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
111714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
111814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
111914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1120f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            deleteNameLookup(dataId);
112125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
112214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
11233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
11243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
1126622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Specific list of structured fields.
11273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
1128622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private final String[] STRUCTURED_FIELDS = new String[] {
1129622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredName.PREFIX, StructuredName.GIVEN_NAME, StructuredName.MIDDLE_NAME,
1130622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredName.FAMILY_NAME, StructuredName.SUFFIX
1131622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        };
11323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1133622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1134622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Parses the supplied display name, but only if the incoming values do
1135622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * not already contain structured name parts. Also, if the display name
1136622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * is not provided, generate one by concatenating first name and last
1137622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * name.
1138622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1139622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private void fixStructuredNameComponents(ContentValues augmented, ContentValues update) {
114067c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final String unstruct = update.getAsString(StructuredName.DISPLAY_NAME);
1141622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
114267c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final boolean touchedUnstruct = !TextUtils.isEmpty(unstruct);
114367c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final boolean touchedStruct = !areAllEmpty(update, STRUCTURED_FIELDS);
1144622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1145622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            if (touchedUnstruct && !touchedStruct) {
11468c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                NameSplitter.Name name = new NameSplitter.Name();
1147622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                mSplitter.split(name, unstruct);
1148622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                name.toValues(update);
114967c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            } else if (!touchedUnstruct
115067c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                    && (touchedStruct || areAnySpecified(update, STRUCTURED_FIELDS))) {
115167c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                // We need to update the display name when any structured components
115267c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                // are specified, even when they are null, which is why we are checking
115367c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                // areAnySpecified.  The touchedStruct in the condition is an optimization:
115467c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                // if there are non-null values, we know for a fact that some values are present.
11558c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                NameSplitter.Name name = new NameSplitter.Name();
1156622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                name.fromValues(augmented);
11574cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                // As the name could be changed, let's guess the name style again.
11584cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                name.fullNameStyle = FullNameStyle.UNDEFINED;
11594cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                mSplitter.guessNameStyle(name);
11605dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
11615dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                final String joined = mSplitter.join(name, true);
1162622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                update.put(StructuredName.DISPLAY_NAME, joined);
11635dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
11645dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                update.put(StructuredName.FULL_NAME_STYLE, name.fullNameStyle);
11655dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                update.put(StructuredName.PHONETIC_NAME_STYLE, name.phoneticNameStyle);
11664cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao            } else if (touchedUnstruct && touchedStruct){
11674cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                if (TextUtils.isEmpty(update.getAsString(StructuredName.FULL_NAME_STYLE))) {
11684cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                    update.put(StructuredName.FULL_NAME_STYLE, mSplitter.guessFullNameStyle(unstruct));
11694cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                }
11704cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                if (TextUtils.isEmpty(update.getAsString(StructuredName.PHONETIC_NAME_STYLE))) {
11714cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                    update.put(StructuredName.PHONETIC_NAME_STYLE, mSplitter.guessPhoneticNameStyle(unstruct));
11724cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                }
1173622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
1174622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1175622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    }
1176622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1177622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    public class StructuredPostalRowHandler extends DataRowHandler {
1178622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private PostalSplitter mSplitter;
1179622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1180622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public StructuredPostalRowHandler(PostalSplitter splitter) {
1181622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            super(StructuredPostal.CONTENT_ITEM_TYPE);
1182622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            mSplitter = splitter;
1183622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1184622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1185622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        @Override
1186622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1187622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredPostalComponents(values, values);
1188622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            return super.insert(db, rawContactId, values);
1189622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1190622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1191622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        @Override
1192622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1193f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
1194622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long dataId = c.getLong(DataUpdateQuery._ID);
1195622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues augmented = getAugmentedValues(db, dataId, values);
1196622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredPostalComponents(augmented, values);
1197f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
1198622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1199622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1200622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1201622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Specific list of structured fields.
1202622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1203622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private final String[] STRUCTURED_FIELDS = new String[] {
1204622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredPostal.STREET, StructuredPostal.POBOX, StructuredPostal.NEIGHBORHOOD,
1205622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredPostal.CITY, StructuredPostal.REGION, StructuredPostal.POSTCODE,
1206622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredPostal.COUNTRY,
1207622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        };
1208622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1209622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1210622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Prepares the given {@link StructuredPostal} row, building
1211622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * {@link StructuredPostal#FORMATTED_ADDRESS} to match the structured
1212622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * values when missing. When structured components are missing, the
1213622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * unstructured value is assigned to {@link StructuredPostal#STREET}.
1214622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1215622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private void fixStructuredPostalComponents(ContentValues augmented, ContentValues update) {
121667c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final String unstruct = update.getAsString(StructuredPostal.FORMATTED_ADDRESS);
121767c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov
121867c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final boolean touchedUnstruct = !TextUtils.isEmpty(unstruct);
121967c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final boolean touchedStruct = !areAllEmpty(update, STRUCTURED_FIELDS);
1220622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1221622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final PostalSplitter.Postal postal = new PostalSplitter.Postal();
1222622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1223622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            if (touchedUnstruct && !touchedStruct) {
1224622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                mSplitter.split(postal, unstruct);
1225622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                postal.toValues(update);
122667c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            } else if (!touchedUnstruct
122767c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                    && (touchedStruct || areAnySpecified(update, STRUCTURED_FIELDS))) {
122867c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                // See comment in
1229622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                postal.fromValues(augmented);
1230622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                final String joined = mSplitter.join(postal);
1231622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                update.put(StructuredPostal.FORMATTED_ADDRESS, joined);
12323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
12333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
12343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
12353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CommonDataRowHandler extends DataRowHandler {
12373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mTypeColumn;
12393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mLabelColumn;
12403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CommonDataRowHandler(String mimetype, String typeColumn, String labelColumn) {
12423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
12433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mTypeColumn = typeColumn;
12443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mLabelColumn = labelColumn;
12453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
12463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
12485ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1249622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            enforceTypeAndLabel(values, values);
1250622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            return super.insert(db, rawContactId, values);
1251622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
12523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1253622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        @Override
1254622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1255f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
1256622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long dataId = c.getLong(DataUpdateQuery._ID);
1257622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues augmented = getAugmentedValues(db, dataId, values);
1258622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            enforceTypeAndLabel(augmented, values);
1259f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
1260622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
12613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1262622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1263622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * If the given {@link ContentValues} defines {@link #mTypeColumn},
1264622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * enforce that {@link #mLabelColumn} only appears when type is
1265622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * {@link BaseTypes#TYPE_CUSTOM}. Exception is thrown otherwise.
1266622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1267622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private void enforceTypeAndLabel(ContentValues augmented, ContentValues update) {
1268622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final boolean hasType = !TextUtils.isEmpty(augmented.getAsString(mTypeColumn));
1269622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final boolean hasLabel = !TextUtils.isEmpty(augmented.getAsString(mLabelColumn));
12703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1271622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            if (hasLabel && !hasType) {
1272622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                // When label exists, assert that some type is defined
1273622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                throw new IllegalArgumentException(mTypeColumn + " must be specified when "
1274622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                        + mLabelColumn + " is defined.");
1275622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
12763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
12773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
12783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class OrganizationDataRowHandler extends CommonDataRowHandler {
12803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public OrganizationDataRowHandler() {
12823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Organization.CONTENT_ITEM_TYPE, Organization.TYPE, Organization.LABEL);
12833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
12843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
12865ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1287a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            String company = values.getAsString(Organization.COMPANY);
1288a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            String title = values.getAsString(Organization.TITLE);
1289a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka
1290a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            long dataId = super.insert(db, rawContactId, values);
1291a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka
129225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
1293a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            insertNameLookupForOrganization(rawContactId, dataId, company, title);
1294a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            return dataId;
12953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
12963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
129814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1299f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
1300a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            long dataId = c.getLong(DataUpdateQuery._ID);
130114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
130214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1303f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
130414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
130531168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov            boolean containsCompany = values.containsKey(Organization.COMPANY);
130631168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov            boolean containsTitle = values.containsKey(Organization.TITLE);
130731168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov            if (containsCompany || containsTitle) {
130831168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                String company;
130931168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov
131031168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                if (containsCompany) {
131131168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    company = values.getAsString(Organization.COMPANY);
131231168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                } else {
131331168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    mSelectionArgs1[0] = String.valueOf(dataId);
131431168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    company = DatabaseUtils.stringForQuery(db,
131531168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            "SELECT " + Organization.COMPANY +
131631168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            " FROM " + Tables.DATA +
131731168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            " WHERE " + Data._ID + "=?", mSelectionArgs1);
131831168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                }
131931168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov
132031168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                String title;
132131168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                if (containsTitle) {
132231168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    title = values.getAsString(Organization.TITLE);
132331168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                } else {
132431168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    mSelectionArgs1[0] = String.valueOf(dataId);
132531168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    title = DatabaseUtils.stringForQuery(db,
132631168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            "SELECT " + Organization.TITLE +
132731168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            " FROM " + Tables.DATA +
132831168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            " WHERE " + Data._ID + "=?", mSelectionArgs1);
132931168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                }
133031168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov
133131168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                deleteNameLookup(dataId);
133231168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                insertNameLookupForOrganization(rawContactId, dataId, company, title);
133331168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov
133431168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                fixRawContactDisplayName(db, rawContactId);
133531168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov            }
133614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
133714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
133814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
133914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
1340a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            long dataId = c.getLong(DataUpdateQuery._ID);
134114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
134214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
134314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
134425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
1345a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            deleteNameLookup(dataId);
134614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
134714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
134814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
134914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
13503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
13513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
13523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_WORK: return 0;
13533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_CUSTOM: return 1;
13543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_OTHER: return 2;
13553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
13563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
13573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
1358a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1359a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1360a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
1361a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return false;
1362a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
13633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
13643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1365e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    public class EmailDataRowHandler extends CommonDataRowHandler {
1366e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1367e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public EmailDataRowHandler() {
1368e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            super(Email.CONTENT_ITEM_TYPE, Email.TYPE, Email.LABEL);
1369e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1370e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1371e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
13725ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
137314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String address = values.getAsString(Email.DATA);
137414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
137514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
137614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
137725abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
1378f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            insertNameLookupForEmail(rawContactId, dataId, address);
137914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
138014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
138114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
138214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
138314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1384f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
138514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
138614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
138714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String address = values.getAsString(Email.DATA);
138814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1389f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
139014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1391f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            deleteNameLookup(dataId);
1392f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            insertNameLookupForEmail(rawContactId, dataId, address);
139325abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
139414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
139514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
139614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
139714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
139814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
139914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
140014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
140114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
140214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1403f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            deleteNameLookup(dataId);
140425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
140514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
1406e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1407e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1408e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
1409e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
1410e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            switch (type) {
1411e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_HOME: return 0;
1412e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_WORK: return 1;
1413e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_CUSTOM: return 2;
1414e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_OTHER: return 3;
1415e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                default: return 1000;
1416e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
1417e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1418e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    }
1419e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
142014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    public class NicknameDataRowHandler extends CommonDataRowHandler {
142114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
142214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public NicknameDataRowHandler() {
142314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super(Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE, Nickname.LABEL);
142414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
142514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
142614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
142714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
142814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String nickname = values.getAsString(Nickname.NAME);
142914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
143014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
143114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
143225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
1433f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            insertNameLookupForNickname(rawContactId, dataId, nickname);
143414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
143514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
143614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
143714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
143814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1439f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
144014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
144114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
144214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String nickname = values.getAsString(Nickname.NAME);
144314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1444f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
144514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1446f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            deleteNameLookup(dataId);
1447f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            insertNameLookupForNickname(rawContactId, dataId, nickname);
144825abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
144914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
145014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
145114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
145214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
145314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
145414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
145514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
145614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
145714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1458f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            deleteNameLookup(dataId);
145925abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
146014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
146114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
146214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    }
146314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
14643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class PhoneDataRowHandler extends CommonDataRowHandler {
14653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
14663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public PhoneDataRowHandler() {
14673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Phone.CONTENT_ITEM_TYPE, Phone.TYPE, Phone.LABEL);
14683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
14693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
14703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
14715ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
14720b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            long dataId;
14730b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            if (values.containsKey(Phone.NUMBER)) {
14740b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String number = values.getAsString(Phone.NUMBER);
14750b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String normalizedNumber = computeNormalizedNumber(number, values);
1476653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
14770b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                dataId = super.insert(db, rawContactId, values);
1478653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
14790b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
1480285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateHasPhoneNumber(db, rawContactId);
148125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                fixRawContactDisplayName(db, rawContactId);
14820b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            } else {
14830b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                dataId = super.insert(db, rawContactId, values);
14840b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            }
1485653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return dataId;
1486653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1487653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1488653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1489653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1490f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
149114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
149214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
14930b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            if (values.containsKey(Phone.NUMBER)) {
14940b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String number = values.getAsString(Phone.NUMBER);
14950b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String normalizedNumber = computeNormalizedNumber(number, values);
1496653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1497f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                super.update(db, values, c, callerIsSyncAdapter);
1498653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
14990b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
1500285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateHasPhoneNumber(db, rawContactId);
150125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                fixRawContactDisplayName(db, rawContactId);
15020b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            } else {
1503f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                super.update(db, values, c, callerIsSyncAdapter);
15040b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            }
150514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
150614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
150714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
150814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
150914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
151014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
151114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
151214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
151314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
151414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            updatePhoneLookup(db, rawContactId, dataId, null, null);
1515285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            mContactAggregator.updateHasPhoneNumber(db, rawContactId);
151625abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
151714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
1518653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1519653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1520653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        private String computeNormalizedNumber(String number, ContentValues values) {
1521e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            String normalizedNumber = null;
1522e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (number != null) {
1523e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                normalizedNumber = PhoneNumberUtils.getStrippedReversed(number);
1524e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
1525653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            values.put(PhoneColumns.NORMALIZED_NUMBER, normalizedNumber);
1526653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return normalizedNumber;
1527653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1528e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1529653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        private void updatePhoneLookup(SQLiteDatabase db, long rawContactId, long dataId,
1530653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                String number, String normalizedNumber) {
1531e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (number != null) {
1532653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                ContentValues phoneValues = new ContentValues();
15335ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.RAW_CONTACT_ID, rawContactId);
1534653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.DATA_ID, dataId);
1535e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, normalizedNumber);
153636045476d2cc7c9c2f985307e87cb6bbc4cfe434Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.MIN_MATCH,
153736045476d2cc7c9c2f985307e87cb6bbc4cfe434Dmitri Plotnikov                        PhoneNumberUtils.toCallerIDMinMatch(number));
153836045476d2cc7c9c2f985307e87cb6bbc4cfe434Dmitri Plotnikov
1539653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                db.replace(Tables.PHONE_LOOKUP, null, phoneValues);
1540653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            } else {
15414da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                mSelectionArgs1[0] = String.valueOf(dataId);
15424da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                db.delete(Tables.PHONE_LOOKUP, PhoneLookupColumns.DATA_ID + "=?", mSelectionArgs1);
1543e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
15443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
15453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
15463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
15473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
15483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
15493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_MOBILE: return 0;
15503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_WORK: return 1;
15513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_HOME: return 2;
15523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_PAGER: return 3;
15533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_CUSTOM: return 4;
15543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_OTHER: return 5;
15553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_WORK: return 6;
15563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_HOME: return 7;
15573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
15583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
15593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
15603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
15613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1562653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    public class GroupMembershipRowHandler extends DataRowHandler {
1563653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1564653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public GroupMembershipRowHandler() {
1565653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            super(GroupMembership.CONTENT_ITEM_TYPE);
1566653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1567653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1568653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1569653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1570653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            resolveGroupSourceIdInValues(rawContactId, db, values, true);
15710be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
15720be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            updateVisibility(rawContactId);
15730be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            return dataId;
1574653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1575653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1576653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1577653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1578f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
157914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1580653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            resolveGroupSourceIdInValues(rawContactId, db, values, false);
1581f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
15820be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            updateVisibility(rawContactId);
15830be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        }
15840be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov
15850be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        @Override
15860be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
15870be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
15880be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            int count = super.delete(db, c);
15890be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            updateVisibility(rawContactId);
15900be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            return count;
15910be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        }
15920be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov
15930be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        private void updateVisibility(long rawContactId) {
1594b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            long contactId = mDbHelper.getContactId(rawContactId);
15950be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            if (contactId != 0) {
1596b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                mDbHelper.updateContactVisible(contactId);
15970be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            }
1598653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1599653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1600653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        private void resolveGroupSourceIdInValues(long rawContactId, SQLiteDatabase db,
1601653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                ContentValues values, boolean isInsert) {
1602653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            boolean containsGroupSourceId = values.containsKey(GroupMembership.GROUP_SOURCE_ID);
1603653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            boolean containsGroupId = values.containsKey(GroupMembership.GROUP_ROW_ID);
1604653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (containsGroupSourceId && containsGroupId) {
1605653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                throw new IllegalArgumentException(
1606653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        "you are not allowed to set both the GroupMembership.GROUP_SOURCE_ID "
1607653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                + "and GroupMembership.GROUP_ROW_ID");
1608653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1609653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1610653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (!containsGroupSourceId && !containsGroupId) {
1611653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                if (isInsert) {
1612653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                    throw new IllegalArgumentException(
1613653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                            "you must set exactly one of GroupMembership.GROUP_SOURCE_ID "
1614653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                    + "and GroupMembership.GROUP_ROW_ID");
1615653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                } else {
1616653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                    return;
1617653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                }
1618653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1619653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1620653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (containsGroupSourceId) {
1621653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                final String sourceId = values.getAsString(GroupMembership.GROUP_SOURCE_ID);
1622ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                final long groupId = getOrMakeGroup(db, rawContactId, sourceId,
1623ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                        mInsertedRawContacts.get(rawContactId));
1624653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(GroupMembership.GROUP_SOURCE_ID);
1625653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.put(GroupMembership.GROUP_ROW_ID, groupId);
1626653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1627653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1628a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1629a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1630a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
1631a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return false;
1632a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1633653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    }
1634653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1635a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov    public class PhotoDataRowHandler extends DataRowHandler {
1636a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1637a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public PhotoDataRowHandler() {
1638a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            super(Photo.CONTENT_ITEM_TYPE);
1639a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1640a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1641a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1642a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1643a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
1644285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            if (!isNewRawContact(rawContactId)) {
1645285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updatePhotoId(db, rawContactId);
1646285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
1647a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return dataId;
1648a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1649a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1650a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1651a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1652f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
1653a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1654f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
1655a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            mContactAggregator.updatePhotoId(db, rawContactId);
1656a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1657a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1658a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1659a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
1660a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
1661a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            int count = super.delete(db, c);
1662a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            mContactAggregator.updatePhotoId(db, rawContactId);
1663a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return count;
1664a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1665a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1666a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1667a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
1668a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return false;
1669a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1670a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov    }
1671a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1672ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    /**
1673ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov     * An entry in group id cache. It maps the combination of (account type, account name
1674ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov     * and source id) to group row id.
1675ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov     */
1676ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    public class GroupIdCacheEntry {
1677ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        String accountType;
1678ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        String accountName;
1679ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        String sourceId;
1680ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        long groupId;
1681ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    }
1682a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
16833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private HashMap<String, DataRowHandler> mDataRowHandlers;
1684b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov    private ContactsDatabaseHelper mDbHelper;
168531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
16864097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov    private NameSplitter mNameSplitter;
1687f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private NameLookupBuilder mNameLookupBuilder;
1688315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
1689315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov    // We will use this much memory (in bits) to optimize the nickname cluster lookup
1690315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov    private static final int NICKNAME_BLOOM_FILTER_SIZE = 0x1FFF;   // =long[128]
1691315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov    private BitSet mNicknameBloomFilter;
1692315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
1693ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    private HashMap<String, SoftReference<String[]>> mNicknameClusterCache = Maps.newHashMap();
1694ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
1695622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    private PostalSplitter mPostalSplitter;
1696622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1697ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    // We don't need a soft cache for groups - the assumption is that there will only
1698ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    // be a small number of contact groups. The cache is keyed off source id.  The value
1699ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    // is a list of groups with this group id.
1700ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    private HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache = Maps.newHashMap();
1701ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
1702622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    private ContactAggregator mContactAggregator;
1703f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private LegacyApiSupport mLegacyApiSupport;
1704a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    private GlobalSearchSupport mGlobalSearchSupport;
1705a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
170620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private ContentValues mValues = new ContentValues();
17071129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private CharArrayBuffer mCharArrayBuffer = new CharArrayBuffer(128);
17085dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    private NameSplitter.Name mName = new NameSplitter.Name();
170920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1710ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov    private volatile CountDownLatch mAccessLatch;
171173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1712ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    private HashMap<Long, Account> mInsertedRawContacts = Maps.newHashMap();
1713b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private HashSet<Long> mUpdatedRawContacts = Sets.newHashSet();
1714a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    private HashSet<Long> mDirtyRawContacts = Sets.newHashSet();
1715b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private HashMap<Long, Object> mUpdatedSyncStates = Maps.newHashMap();
1716de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov
17171a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey    private boolean mVisibleTouched = false;
17181a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey
171981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov    private boolean mSyncToNetwork;
172081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov
17214cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao    private Locale mCurrentLocale;
17224f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
17234f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public boolean onCreate() {
1724de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        super.onCreate();
1725ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov        try {
1726ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov            return initialize();
1727ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov        } catch (RuntimeException e) {
1728ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov            Log.e(TAG, "Cannot start provider", e);
1729ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov            return false;
1730ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov        }
1731ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov    }
173235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1733ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov    private boolean initialize() {
1734de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final Context context = getContext();
1735b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        mDbHelper = (ContactsDatabaseHelper)getDatabaseHelper();
1736a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mGlobalSearchSupport = new GlobalSearchSupport(this);
1737b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        mLegacyApiSupport = new LegacyApiSupport(context, mDbHelper, this, mGlobalSearchSupport);
1738d076a108d58b30591f197e1b90fa8de60999c499Dmitri Plotnikov        mContactAggregator = new ContactAggregator(this, mDbHelper);
17390e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff        mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true));
1740a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1741b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        final SQLiteDatabase db = mDbHelper.getReadableDatabase();
1742653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1743c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement = db.compileStatement(
1744653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "UPDATE " + Tables.DATA +
1745653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " SET " + Data.IS_PRIMARY + "=(_id=?)" +
1746653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " WHERE " + DataColumns.MIMETYPE_ID + "=?" +
1747653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "   AND " + Data.RAW_CONTACT_ID + "=?");
1748653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1749c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement = db.compileStatement(
1750653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "UPDATE " + Tables.DATA +
1751653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " SET " + Data.IS_SUPER_PRIMARY + "=(" + Data._ID + "=?)" +
1752653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " WHERE " + DataColumns.MIMETYPE_ID + "=?" +
1753653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "   AND " + Data.RAW_CONTACT_ID + " IN (" +
1754653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        "SELECT " + RawContacts._ID +
1755653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        " FROM " + Tables.RAW_CONTACTS +
1756653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        " WHERE " + RawContacts.CONTACT_ID + " =(" +
1757653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                "SELECT " + RawContacts.CONTACT_ID +
1758653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                " FROM " + Tables.RAW_CONTACTS +
1759653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                " WHERE " + RawContacts._ID + "=?))");
1760653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
176125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        mRawContactDisplayNameUpdate = db.compileStatement(
176225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                "UPDATE " + Tables.RAW_CONTACTS +
17635dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                " SET " +
17645dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        RawContacts.DISPLAY_NAME_SOURCE + "=?," +
17655dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        RawContacts.DISPLAY_NAME_PRIMARY + "=?," +
17665dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        RawContacts.DISPLAY_NAME_ALTERNATIVE + "=?," +
17675dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        RawContacts.PHONETIC_NAME + "=?," +
17685dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        RawContacts.PHONETIC_NAME_STYLE + "=?," +
17695dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        RawContacts.SORT_KEY_PRIMARY + "=?," +
17705dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        RawContacts.SORT_KEY_ALTERNATIVE + "=?" +
177125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                " WHERE " + RawContacts._ID + "=?");
17723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1773a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        mLastStatusUpdate = db.compileStatement(
1774a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov                "UPDATE " + Tables.CONTACTS +
1775a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov                " SET " + ContactsColumns.LAST_STATUS_UPDATE_ID + "=" +
1776a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        "(SELECT " + DataColumns.CONCRETE_ID +
1777a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        " FROM " + Tables.STATUS_UPDATES +
1778a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        " JOIN " + Tables.DATA +
1779a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        "   ON (" + StatusUpdatesColumns.DATA_ID + "="
1780a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                                + DataColumns.CONCRETE_ID + ")" +
1781a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        " JOIN " + Tables.RAW_CONTACTS +
1782a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        "   ON (" + DataColumns.CONCRETE_RAW_CONTACT_ID + "="
1783a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                                + RawContactsColumns.CONCRETE_ID + ")" +
1784a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        " WHERE " + RawContacts.CONTACT_ID + "=?" +
17850a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        " ORDER BY " + StatusUpdates.STATUS_TIMESTAMP + " DESC,"
17860a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                                + StatusUpdates.STATUS +
1787a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov                        " LIMIT 1)" +
1788a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov                " WHERE " + ContactsColumns.CONCRETE_ID + "=?");
1789e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
17904cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        initByLocale(context);
17914097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
1792f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        mNameLookupInsert = db.compileStatement("INSERT OR IGNORE INTO " + Tables.NAME_LOOKUP + "("
1793f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                + NameLookupColumns.RAW_CONTACT_ID + "," + NameLookupColumns.DATA_ID + ","
1794f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                + NameLookupColumns.NAME_TYPE + "," + NameLookupColumns.NORMALIZED_NAME
1795f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                + ") VALUES (?,?,?,?)");
1796f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        mNameLookupDelete = db.compileStatement("DELETE FROM " + Tables.NAME_LOOKUP + " WHERE "
1797f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                + NameLookupColumns.DATA_ID + "=?");
1798f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
1799a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        mStatusUpdateInsert = db.compileStatement(
1800a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                "INSERT INTO " + Tables.STATUS_UPDATES + "("
1801a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        + StatusUpdatesColumns.DATA_ID + ", "
18020a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS + ","
18030a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS_RES_PACKAGE + ","
18040a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS_ICON + ","
18050a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS_LABEL + ")" +
18060a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                " VALUES (?,?,?,?,?)");
1807a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
1808a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        mStatusUpdateReplace = db.compileStatement(
1809a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                "INSERT OR REPLACE INTO " + Tables.STATUS_UPDATES + "("
1810a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        + StatusUpdatesColumns.DATA_ID + ", "
18110a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS_TIMESTAMP + ","
18120a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS + ","
18130a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS_RES_PACKAGE + ","
18140a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS_ICON + ","
18150a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS_LABEL + ")" +
18160a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                " VALUES (?,?,?,?,?,?)");
1817a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
1818a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        mStatusUpdateAutoTimestamp = db.compileStatement(
1819a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                "UPDATE " + Tables.STATUS_UPDATES +
18200a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                " SET " + StatusUpdates.STATUS_TIMESTAMP + "=?,"
18210a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS + "=?" +
1822a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                " WHERE " + StatusUpdatesColumns.DATA_ID + "=?"
18230a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + " AND " + StatusUpdates.STATUS + "!=?");
18240a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
18250a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        mStatusAttributionUpdate = db.compileStatement(
18260a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                "UPDATE " + Tables.STATUS_UPDATES +
18270a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                " SET " + StatusUpdates.STATUS_RES_PACKAGE + "=?,"
18280a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS_ICON + "=?,"
18290a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                        + StatusUpdates.STATUS_LABEL + "=?" +
18300a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                " WHERE " + StatusUpdatesColumns.DATA_ID + "=?");
1831a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
1832a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        mStatusUpdateDelete = db.compileStatement(
1833a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                "DELETE FROM " + Tables.STATUS_UPDATES +
1834a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                " WHERE " + StatusUpdatesColumns.DATA_ID + "=?");
1835a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
1836f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov        // When setting NAME_VERIFIED to 1 on a raw contact, reset it to 0
1837f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov        // on all other raw contacts in the same aggregate
1838f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov        mResetNameVerifiedForOtherRawContacts = db.compileStatement(
1839f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                "UPDATE " + Tables.RAW_CONTACTS +
1840f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                " SET " + RawContacts.NAME_VERIFIED + "=0" +
1841f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                " WHERE " + RawContacts.CONTACT_ID + "=(" +
1842f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                        "SELECT " + RawContacts.CONTACT_ID +
1843f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                        " FROM " + Tables.RAW_CONTACTS +
1844f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                        " WHERE " + RawContacts._ID + "=?)" +
1845f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                " AND " + RawContacts._ID + "!=?");
1846f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov
18473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers = new HashMap<String, DataRowHandler>();
18483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1849e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, new EmailDataRowHandler());
18503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE,
18513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new CommonDataRowHandler(Im.CONTENT_ITEM_TYPE, Im.TYPE, Im.LABEL));
185267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler(
185367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, StructuredPostal.LABEL));
18543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, new OrganizationDataRowHandler());
18553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, new PhoneDataRowHandler());
185614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new NicknameDataRowHandler());
18573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE,
18583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new StructuredNameRowHandler(mNameSplitter));
1859622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        mDataRowHandlers.put(StructuredPostal.CONTENT_ITEM_TYPE,
1860622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                new StructuredPostalRowHandler(mPostalSplitter));
1861a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        mDataRowHandlers.put(GroupMembership.CONTENT_ITEM_TYPE, new GroupMembershipRowHandler());
1862a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        mDataRowHandlers.put(Photo.CONTENT_ITEM_TYPE, new PhotoDataRowHandler());
18633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
18643d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        if (isLegacyContactImportNeeded()) {
1865568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            importLegacyContactsAsync();
18663d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
1867568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1868c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov        verifyAccounts();
186970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong
1870f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov        mMimeTypeIdEmail = mDbHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE);
1871f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov        mMimeTypeIdIm = mDbHelper.getMimeTypeId(Im.CONTENT_ITEM_TYPE);
18721129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        mMimeTypeIdStructuredName = mDbHelper.getMimeTypeId(StructuredName.CONTENT_ITEM_TYPE);
18731129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        mMimeTypeIdOrganization = mDbHelper.getMimeTypeId(Organization.CONTENT_ITEM_TYPE);
18741129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        mMimeTypeIdNickname = mDbHelper.getMimeTypeId(Nickname.CONTENT_ITEM_TYPE);
18751129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        mMimeTypeIdPhone = mDbHelper.getMimeTypeId(Phone.CONTENT_ITEM_TYPE);
1876315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        preloadNicknameBloomFilter();
18771f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        return (db != null);
18784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
18794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
18804cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao    private void initByLocale(Context context) {
18814cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        mCurrentLocale = getLocale();
18824cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        if (mCurrentLocale == null) {
18834cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao            return;
18844cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        }
18854cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        mNameSplitter = new NameSplitter(
18864cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                context.getString(com.android.internal.R.string.common_name_prefixes),
18874cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                context.getString(com.android.internal.R.string.common_last_name_prefixes),
18884cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                context.getString(com.android.internal.R.string.common_name_suffixes),
18894cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                context.getString(com.android.internal.R.string.common_name_conjunctions),
18904cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                mCurrentLocale);
18914cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter);
18924cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        mPostalSplitter = new PostalSplitter(mCurrentLocale);
18934cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao    }
18944cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao
18954cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao    @Override
18964cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao    public void onConfigurationChanged (Configuration newConfig) {
18974cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        if (newConfig != null && mCurrentLocale != null
18984cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                && mCurrentLocale.equals(newConfig.locale)) {
18994cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao            initByLocale(getContext());
19004cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        }
19014cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao    }
1902c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov    protected void verifyAccounts() {
1903c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov        AccountManager.get(getContext()).addOnAccountsUpdatedListener(this, null, false);
1904c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov        onAccountsUpdated(AccountManager.get(getContext()).getAccounts());
1905c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov    }
1906c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov
190731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    /* Visible for testing */
1908de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    @Override
1909b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov    protected ContactsDatabaseHelper getDatabaseHelper(final Context context) {
1910b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        return ContactsDatabaseHelper.getInstance(context);
191131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    }
191231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
1913013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    /* package */ NameSplitter getNameSplitter() {
1914013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov        return mNameSplitter;
1915013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    }
1916013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov
19175dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    /* Visible for testing */
19185dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    protected Locale getLocale() {
19195dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        return Locale.getDefault();
19205dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    }
19215dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
19223d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    protected boolean isLegacyContactImportNeeded() {
19233d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
19243d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        return prefs.getInt(PREF_CONTACTS_IMPORTED, 0) < PREF_CONTACTS_IMPORT_VERSION;
19253d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
19263d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1927568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    protected LegacyContactImporter getLegacyContactImporter() {
1928568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return new LegacyContactImporter(getContext(), this);
1929568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1930568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1931568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /**
1932568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * Imports legacy contacts in a separate thread.  As long as the import process is running
1933568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * all other access to the contacts is blocked.
1934568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     */
1935568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    private void importLegacyContactsAsync() {
1936ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        mAccessLatch = new CountDownLatch(1);
1937568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1938568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        Thread importThread = new Thread("LegacyContactImport") {
1939568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            @Override
1940568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            public void run() {
1941568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                if (importLegacyContacts()) {
1942d076a108d58b30591f197e1b90fa8de60999c499Dmitri Plotnikov                    // TODO aggregate all newly added raw contacts
1943568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1944568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                    /*
1945568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     * When the import process is done, we can unlock the provider and
1946568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     * start aggregating the imported contacts asynchronously.
1947568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     */
1948ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch.countDown();
1949ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch = null;
1950568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                }
1951568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            }
1952568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        };
1953568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1954568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        importThread.start();
1955568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1956568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
19573d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private boolean importLegacyContacts() {
1958568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        LegacyContactImporter importer = getLegacyContactImporter();
1959568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        if (importLegacyContacts(importer)) {
19603d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
19613d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            Editor editor = prefs.edit();
19623d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            editor.putInt(PREF_CONTACTS_IMPORTED, PREF_CONTACTS_IMPORT_VERSION);
19633d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            editor.commit();
19643d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return true;
19653d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        } else {
19663d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return false;
19673d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
19683d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
19693d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
19703d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /* Visible for testing */
1971568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /* package */ boolean importLegacyContacts(LegacyContactImporter importer) {
19720e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff        boolean aggregatorEnabled = mContactAggregator.isEnabled();
19733d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        mContactAggregator.setEnabled(false);
19743d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        try {
19753d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            importer.importContacts();
19760e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff            mContactAggregator.setEnabled(aggregatorEnabled);
19773d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return true;
19783d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        } catch (Throwable e) {
19793d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov           Log.e(TAG, "Legacy contact import failed", e);
19803d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov           return false;
19813d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
19823d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
19833d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1984a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
1985a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Wipes all data from the contacts database.
1986a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
1987a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /* package */ void wipeData() {
1988b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        mDbHelper.wipeData();
1989a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1990a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1991568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /**
1992568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * While importing and aggregating contacts, this content provider will
1993568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * block all attempts to change contacts data. In particular, it will hold
1994568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * up all contact syncs. As soon as the import process is complete, all
1995568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * processes waiting to write to the provider are unblocked and can proceed
1996568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * to compete for the database transaction monitor.
1997568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     */
1998568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    private void waitForAccess() {
1999ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        CountDownLatch latch = mAccessLatch;
2000ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        if (latch != null) {
2001ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov            while (true) {
2002ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                try {
2003ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    latch.await();
2004ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch = null;
2005ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    return;
2006ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                } catch (InterruptedException e) {
200781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                    Thread.currentThread().interrupt();
2008ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                }
2009ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov            }
2010568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        }
2011568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2012568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2013568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
2014568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public Uri insert(Uri uri, ContentValues values) {
2015568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
2016568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.insert(uri, values);
2017568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2018568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2019568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
2020568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
2021568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
2022568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.update(uri, values, selection, selectionArgs);
2023568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2024568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2025568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
2026568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public int delete(Uri uri, String selection, String[] selectionArgs) {
2027568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
2028568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.delete(uri, selection, selectionArgs);
2029568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2030568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2031568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
2032568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
2033568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            throws OperationApplicationException {
2034568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
2035568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.applyBatch(operations);
2036568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2037568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
20384f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
2039285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    protected void onBeginTransaction() {
2040bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
2041b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "onBeginTransaction");
2042b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2043285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        super.onBeginTransaction();
20441ea29714ef8fdd62b71f265f27391c22f4a50340Fred Quintana        mContactAggregator.clearPendingAggregations();
2045b5a4add17815167d20a90645779df34cdf45280dFred Quintana        clearTransactionalChanges();
2046b5a4add17815167d20a90645779df34cdf45280dFred Quintana    }
2047b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2048b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private void clearTransactionalChanges() {
2049285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        mInsertedRawContacts.clear();
2050b5a4add17815167d20a90645779df34cdf45280dFred Quintana        mUpdatedRawContacts.clear();
2051df9db5e99572ce9760eb265683134c1f3293928fFred Quintana        mUpdatedSyncStates.clear();
2052a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov        mDirtyRawContacts.clear();
2053285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
2054285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
2055285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    @Override
2056285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    protected void beforeTransactionCommit() {
20571129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov
2058bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
2059b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "beforeTransactionCommit");
2060b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2061285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        super.beforeTransactionCommit();
2062b5a4add17815167d20a90645779df34cdf45280dFred Quintana        flushTransactionalChanges();
20631ea29714ef8fdd62b71f265f27391c22f4a50340Fred Quintana        mContactAggregator.aggregateInTransaction(mDb);
20641a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (mVisibleTouched) {
20651a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = false;
2066b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            mDbHelper.updateAllVisible();
20671a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        }
2068b5a4add17815167d20a90645779df34cdf45280dFred Quintana    }
2069b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2070b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private void flushTransactionalChanges() {
2071bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
2072b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "flushTransactionChanges");
2073b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
20741129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov
207508e42c9c153a60bf2e7c71dd40bf84bb5fc93555Dmitri Plotnikov        for (long rawContactId : mInsertedRawContacts.keySet()) {
2076d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov            updateRawContactDisplayName(mDb, rawContactId);
2077d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov            mContactAggregator.onRawContactInsert(mDb, rawContactId);
2078285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        }
2079b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2080a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov        if (!mDirtyRawContacts.isEmpty()) {
2081a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.setLength(0);
2082a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.append(UPDATE_RAW_CONTACT_SET_DIRTY_SQL);
2083a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            appendIds(mSb, mDirtyRawContacts);
2084a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.append(")");
2085a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mDb.execSQL(mSb.toString());
2086a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov        }
2087a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov
2088b5a4add17815167d20a90645779df34cdf45280dFred Quintana        if (!mUpdatedRawContacts.isEmpty()) {
2089a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.setLength(0);
2090a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.append(UPDATE_RAW_CONTACT_SET_VERSION_SQL);
2091a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            appendIds(mSb, mUpdatedRawContacts);
2092a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.append(")");
2093a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mDb.execSQL(mSb.toString());
2094b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2095b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2096b5a4add17815167d20a90645779df34cdf45280dFred Quintana        for (Map.Entry<Long, Object> entry : mUpdatedSyncStates.entrySet()) {
2097b5a4add17815167d20a90645779df34cdf45280dFred Quintana            long id = entry.getKey();
2098b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            mDbHelper.getSyncState().update(mDb, id, entry.getValue());
2099b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2100b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2101b5a4add17815167d20a90645779df34cdf45280dFred Quintana        clearTransactionalChanges();
2102b5a4add17815167d20a90645779df34cdf45280dFred Quintana    }
2103b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2104a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    /**
2105a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov     * Appends comma separated ids.
2106a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov     * @param ids Should not be empty
2107a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov     */
2108a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    private void appendIds(StringBuilder sb, HashSet<Long> ids) {
2109b5a4add17815167d20a90645779df34cdf45280dFred Quintana        for (long id : ids) {
2110a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            sb.append(id).append(',');
2111b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2112a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov
2113a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov        sb.setLength(sb.length() - 1); // Yank the last comma
2114285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
2115285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
2116285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    @Override
2117cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    protected void notifyChange() {
211881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        notifyChange(mSyncToNetwork);
211981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        mSyncToNetwork = false;
212081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov    }
212181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov
212281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov    protected void notifyChange(boolean syncToNetwork) {
212381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null,
212481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                syncToNetwork);
2125cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    }
2126568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2127285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    private boolean isNewRawContact(long rawContactId) {
2128ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        return mInsertedRawContacts.containsKey(rawContactId);
2129285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
2130285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
21313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private DataRowHandler getDataRowHandler(final String mimeType) {
21323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        DataRowHandler handler = mDataRowHandlers.get(mimeType);
21333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (handler == null) {
21343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            handler = new CustomDataRowHandler(mimeType);
21353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mDataRowHandlers.put(mimeType, handler);
21363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
21373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        return handler;
21383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
21393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
21404f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
2141de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected Uri insertInTransaction(Uri uri, ContentValues values) {
2142bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
21431129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov            Log.v(TAG, "insertInTransaction: " + uri + " " + values);
2144b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2145f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana
2146f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        final boolean callerIsSyncAdapter =
2147f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false);
2148f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana
2149a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
2150a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
215135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2152a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        switch (match) {
215335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
2154b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                id = mDbHelper.getSyncState().insert(mDb, values);
215535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                break;
215635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2157d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
2158d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                insertContact(values);
21596bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
21606bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
21616bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
21625ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
2163f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                id = insertRawContact(uri, values);
2164f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
2165a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
2166a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
2167a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
21685ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
21695ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1));
2170f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                id = insertData(values, callerIsSyncAdapter);
2171f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
2172a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
2173a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
2174a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2175a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case DATA: {
2176f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                id = insertData(values, callerIsSyncAdapter);
2177f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
2178a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
2179a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
2180a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2181ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
2182f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                id = insertGroup(uri, values, callerIsSyncAdapter);
2183f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
2184ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2185ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2186ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2187eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
21885aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                id = insertSettings(uri, values);
218943880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov                mSyncToNetwork |= !callerIsSyncAdapter;
2190eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
2191eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
2192eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
219382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES: {
219482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                id = insertStatusUpdate(values);
21951f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                break;
21961f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
21971f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2198a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            default:
219981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                mSyncToNetwork = true;
2200f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.insert(uri, values);
2201a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
2202a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
22037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        if (id < 0) {
22047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return null;
22057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
22067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
2207de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return ContentUris.withAppendedId(uri, id);
2208a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
2209a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2210a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
2211e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * If account is non-null then store it in the values. If the account is
2212e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * already specified in the values then it must be consistent with the
2213e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * account, if it is non-null.
2214e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *
2215e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * @param uri Current {@link Uri} being operated on.
2216e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * @param values {@link ContentValues} to read and possibly update.
2217e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * @throws IllegalArgumentException when only one of
2218e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *             {@link RawContacts#ACCOUNT_NAME} or
2219e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *             {@link RawContacts#ACCOUNT_TYPE} is specified, leaving the
2220e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *             other undefined.
2221e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * @throws IllegalArgumentException when {@link RawContacts#ACCOUNT_NAME}
2222e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *             and {@link RawContacts#ACCOUNT_TYPE} are inconsistent between
2223e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *             the given {@link Uri} and {@link ContentValues}.
22247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
2225e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey    private Account resolveAccount(Uri uri, ContentValues values) throws IllegalArgumentException {
2226f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME);
2227f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE);
2228e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType);
2229f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
2230f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String valueAccountName = values.getAsString(RawContacts.ACCOUNT_NAME);
2231f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String valueAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
2232e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean partialValues = TextUtils.isEmpty(valueAccountName)
2233e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                ^ TextUtils.isEmpty(valueAccountType);
2234e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
2235e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (partialUri || partialValues) {
2236e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            // Throw when either account is incomplete
2237e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            throw new IllegalArgumentException("Must specify both or neither of"
2238e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                    + " ACCOUNT_NAME and ACCOUNT_TYPE");
2239e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        }
2240e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
2241e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // Accounts are valid by only checking one parameter, since we've
2242e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // already ruled out partial accounts.
2243e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean validUri = !TextUtils.isEmpty(accountName);
2244e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean validValues = !TextUtils.isEmpty(valueAccountName);
2245e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
2246e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (validValues && validUri) {
2247e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            // Check that accounts match when both present
2248e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            final boolean accountMatch = TextUtils.equals(accountName, valueAccountName)
2249e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                    && TextUtils.equals(accountType, valueAccountType);
2250e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            if (!accountMatch) {
2251e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                throw new IllegalArgumentException("When both specified, "
2252e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                        + " ACCOUNT_NAME and ACCOUNT_TYPE must match");
2253e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            }
2254e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        } else if (validUri) {
2255e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            // Fill values from Uri when not present
2256f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            values.put(RawContacts.ACCOUNT_NAME, accountName);
2257f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            values.put(RawContacts.ACCOUNT_TYPE, accountType);
2258e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        } else if (validValues) {
2259f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            accountName = valueAccountName;
2260f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            accountType = valueAccountType;
2261e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        } else {
2262e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            return null;
2263f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
2264f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
2265e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // Use cached Account object when matches, otherwise create
2266f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (mAccount == null
2267f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                || !mAccount.name.equals(accountName)
2268f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                || !mAccount.type.equals(accountType)) {
2269f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            mAccount = new Account(accountName, accountType);
2270035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
2271f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
2272e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        return mAccount;
22737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
22747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
22757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
2276d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov     * Inserts an item in the contacts table
22776bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     *
22786bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @param values the values for the new row
22796bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @return the row ID of the newly created row
22806bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     */
2281d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertContact(ContentValues values) {
2282de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        throw new UnsupportedOperationException("Aggregate contacts are created automatically");
22836bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    }
22846bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
22856bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    /**
2286a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the contacts table
2287a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
2288f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov     * @param uri the values for the new row
2289f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov     * @param values the account this contact should be associated with. may be null.
2290a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
2291a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
2292f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    private long insertRawContact(Uri uri, ContentValues values) {
2293f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.clear();
2294f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.putAll(values);
2295f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.putNull(RawContacts.CONTACT_ID);
2296f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
2297e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final Account account = resolveAccount(uri, mValues);
22987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
22993d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        if (values.containsKey(RawContacts.DELETED)
23003d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov                && values.getAsInteger(RawContacts.DELETED) != 0) {
2301f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
23023d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
23033d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
2304f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        long rawContactId = mDb.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, mValues);
2305023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        mContactAggregator.markNewForAggregation(rawContactId);
2306285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
2307285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        // Trigger creation of a Contact based on this RawContact at the end of transaction
2308e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        mInsertedRawContacts.put(rawContactId, account);
2309f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
2310023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        return rawContactId;
2311a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
2312a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2313a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
2314a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the data table
2315a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
2316a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
2317a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
2318a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
2319f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana    private long insertData(ContentValues values, boolean callerIsSyncAdapter) {
2320a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
2321de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.clear();
2322de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.putAll(values);
232367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
2324de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID);
232520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2326de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace package with internal mapping
2327de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String packageName = mValues.getAsString(Data.RES_PACKAGE);
2328de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (packageName != null) {
2329b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName));
2330de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
2331de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.RES_PACKAGE);
2332508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
2333de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace mimetype with internal mapping
2334de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String mimeType = mValues.getAsString(Data.MIMETYPE);
2335de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (TextUtils.isEmpty(mimeType)) {
2336de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            throw new IllegalArgumentException(Data.MIMETYPE + " is required");
2337de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
23384097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
2339b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.getMimeTypeId(mimeType));
2340de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
2341a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
2342a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        DataRowHandler rowHandler = getDataRowHandler(mimeType);
2343a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        id = rowHandler.insert(mDb, rawContactId, mValues);
2344f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (!callerIsSyncAdapter) {
2345de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            setRawContactDirty(rawContactId);
2346a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
2347b5a4add17815167d20a90645779df34cdf45280dFred Quintana        mUpdatedRawContacts.add(rawContactId);
2348a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
2349a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        if (rowHandler.isAggregationRequired()) {
2350a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            triggerAggregation(rawContactId);
2351a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
2352a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        return id;
23534f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
23544f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
23558e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov    private void triggerAggregation(long rawContactId) {
23568e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        if (!mContactAggregator.isEnabled()) {
23578e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            return;
23588e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        }
23598e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
2360b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        int aggregationMode = mDbHelper.getAggregationMode(rawContactId);
2361f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        switch (aggregationMode) {
23628e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DISABLED:
23638e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                break;
23648e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
23658e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DEFAULT: {
2366421782cb554e5050cf62a86b98df6520038dcd15Dmitri Plotnikov                mContactAggregator.markForAggregation(rawContactId);
2367f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
23688e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
23698e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
23708e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_SUSPENDED: {
2371b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                long contactId = mDbHelper.getContactId(rawContactId);
2372f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
23738e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                if (contactId != 0) {
23748e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                    mContactAggregator.updateAggregateData(contactId);
23758e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                }
2376f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
23778e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
2378f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
2379c100221f706afc08409e8317a27d6850b11c54d3Omari Stephens            case RawContacts.AGGREGATION_MODE_IMMEDIATE: {
2380b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                long contactId = mDbHelper.getContactId(rawContactId);
23818e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                mContactAggregator.aggregateContact(mDb, rawContactId, contactId);
2382f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
23838e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
2384f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        }
2385f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
2386f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
2387a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
23885ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * Returns the group id of the group with sourceId and the same account as rawContactId.
23899261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * If the group doesn't already exist then it is first created,
23909261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param db SQLiteDatabase to use for this operation
23915ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * @param rawContactId the contact this group is associated with
23929261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param sourceId the sourceIf of the group to query or create
23939261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @return the group id of the existing or created group
23949261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalArgumentException if the contact is not associated with an account
23959261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalStateException if a group needs to be created but the creation failed
23969261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     */
2397ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    private long getOrMakeGroup(SQLiteDatabase db, long rawContactId, String sourceId,
2398ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            Account account) {
2399ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
2400ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        if (account == null) {
24014da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(rawContactId);
2402ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            Cursor c = db.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS,
24034da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    RawContacts._ID + "=?", mSelectionArgs1, null, null, null);
2404ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            try {
2405ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                if (c.moveToFirst()) {
2406ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    String accountName = c.getString(RawContactsQuery.ACCOUNT_NAME);
2407ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    String accountType = c.getString(RawContactsQuery.ACCOUNT_TYPE);
2408ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
2409ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                        account = new Account(accountName, accountType);
2410ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    }
24119261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
2412ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            } finally {
2413ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                c.close();
24149261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
24159261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
2416ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
24179261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        if (account == null) {
24189261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            throw new IllegalArgumentException("if the groupmembership only "
2419ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    + "has a sourceid the the contact must be associated with "
24209261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "an account");
24219261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
24229261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
2423ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        ArrayList<GroupIdCacheEntry> entries = mGroupIdCache.get(sourceId);
2424ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        if (entries == null) {
2425ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            entries = new ArrayList<GroupIdCacheEntry>(1);
2426ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            mGroupIdCache.put(sourceId, entries);
2427ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        }
2428ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
2429ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        int count = entries.size();
2430ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        for (int i = 0; i < count; i++) {
2431ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            GroupIdCacheEntry entry = entries.get(i);
2432ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            if (entry.accountName.equals(account.name) && entry.accountType.equals(account.type)) {
2433ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                return entry.groupId;
2434ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            }
2435ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        }
2436ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
2437ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        GroupIdCacheEntry entry = new GroupIdCacheEntry();
2438ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        entry.accountName = account.name;
2439ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        entry.accountType = account.type;
2440ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        entry.sourceId = sourceId;
2441ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        entries.add(0, entry);
2442ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
24439261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // look up the group that contains this sourceId and has the same account name and type
24445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        // as the contact refered to by rawContactId
2445ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        Cursor c = db.query(Tables.GROUPS, new String[]{RawContacts._ID},
24469261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Clauses.GROUP_HAS_ACCOUNT_AND_SOURCE_ID,
2447df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                new String[]{sourceId, account.name, account.type}, null, null, null);
24489261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
2449ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            if (c.moveToFirst()) {
2450ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                entry.groupId = c.getLong(0);
24519261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            } else {
24529261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                ContentValues groupValues = new ContentValues();
2453df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                groupValues.put(Groups.ACCOUNT_NAME, account.name);
2454df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                groupValues.put(Groups.ACCOUNT_TYPE, account.type);
24559261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                groupValues.put(Groups.SOURCE_ID, sourceId);
24569261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                long groupId = db.insert(Tables.GROUPS, Groups.ACCOUNT_NAME, groupValues);
24579261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (groupId < 0) {
24589261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    throw new IllegalStateException("unable to create a new group with "
24599261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            + "this sourceid: " + groupValues);
24609261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
2461ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                entry.groupId = groupId;
24629261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
24639261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
24649261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
24659261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
2466ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
2467ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        return entry.groupId;
24689261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    }
24699261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
2470d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov    private interface DisplayNameQuery {
24711129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        public static final String RAW_SQL =
24721129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                "SELECT "
24731129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        + DataColumns.MIMETYPE_ID + ","
24741129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        + Data.IS_PRIMARY + ","
24751129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        + Data.DATA1 + ","
24765dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA2 + ","
24775dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA3 + ","
24785dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA4 + ","
24795dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA5 + ","
24805dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA6 + ","
24815dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA7 + ","
24825dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA8 + ","
24835dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA9 + ","
24845dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA10 + ","
24855dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA11 +
24861129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                " FROM " + Tables.DATA +
24871129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                " WHERE " + Data.RAW_CONTACT_ID + "=?" +
24881129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        " AND (" + Data.DATA1 + " NOT NULL OR " +
24891129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                                Organization.TITLE + " NOT NULL)";
2490d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
2491d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov        public static final int MIMETYPE = 0;
2492d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov        public static final int IS_PRIMARY = 1;
24935dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int DATA1 = 2;
24945dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int GIVEN_NAME = 3;                         // data2
24955dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int FAMILY_NAME = 4;                        // data3
24965dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int PREFIX = 5;                             // data4
24975dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int TITLE = 5;                              // data4
24985dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int MIDDLE_NAME = 6;                        // data5
24995dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int SUFFIX = 7;                             // data6
25005dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int PHONETIC_GIVEN_NAME = 8;                // data7
25015dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int PHONETIC_MIDDLE_NAME = 9;               // data8
25025dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int ORGANIZATION_PHONETIC_NAME = 9;         // data8
25035dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int PHONETIC_FAMILY_NAME = 10;              // data9
25045dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int FULL_NAME_STYLE = 11;                   // data10
25055dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int ORGANIZATION_PHONETIC_NAME_STYLE = 11;  // data10
25065dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int PHONETIC_NAME_STYLE = 12;               // data11
2507d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov    }
2508d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
2509d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov    /**
2510d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov     * Updates a raw contact display name based on data rows, e.g. structured name,
2511d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov     * organization, email etc.
2512d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov     */
2513d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov    private void updateRawContactDisplayName(SQLiteDatabase db, long rawContactId) {
2514bca1c8b44f99528fc123d5547723e44771e8e934Mike Lockwood        int bestDisplayNameSource = DisplayNameSources.UNDEFINED;
25155dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        NameSplitter.Name bestName = null;
25165dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String bestDisplayName = null;
25175dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String bestPhoneticName = null;
25185dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        int bestPhoneticNameStyle = PhoneticNameStyle.UNDEFINED;
2519d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
25201129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(rawContactId);
25211129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        Cursor c = db.rawQuery(DisplayNameQuery.RAW_SQL, mSelectionArgs1);
2522d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov        try {
2523d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov            while (c.moveToNext()) {
25241129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                int mimeType = c.getInt(DisplayNameQuery.MIMETYPE);
25255dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                int source = getDisplayNameSource(mimeType);
25265dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                if (source < bestDisplayNameSource || source == DisplayNameSources.UNDEFINED) {
25275dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    continue;
25285dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                }
25291129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov
25305dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                if (source == bestDisplayNameSource && c.getInt(DisplayNameQuery.IS_PRIMARY) == 0) {
25315dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    continue;
2532d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov                }
25331129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov
25345dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                if (mimeType == mMimeTypeIdStructuredName) {
25355dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    NameSplitter.Name name;
25365dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    if (bestName != null) {
25375dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        name = new NameSplitter.Name();
25385dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    } else {
25395dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        name = mName;
25405dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        name.clear();
25415dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    }
25425dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.prefix = c.getString(DisplayNameQuery.PREFIX);
25435dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.givenNames = c.getString(DisplayNameQuery.GIVEN_NAME);
25445dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.middleName = c.getString(DisplayNameQuery.MIDDLE_NAME);
25455dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.familyName = c.getString(DisplayNameQuery.FAMILY_NAME);
25465dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.suffix = c.getString(DisplayNameQuery.SUFFIX);
25475dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.fullNameStyle = c.isNull(DisplayNameQuery.FULL_NAME_STYLE)
25485dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            ? FullNameStyle.UNDEFINED
25495dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            : c.getInt(DisplayNameQuery.FULL_NAME_STYLE);
25505dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.phoneticFamilyName = c.getString(DisplayNameQuery.PHONETIC_FAMILY_NAME);
25515dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.phoneticMiddleName = c.getString(DisplayNameQuery.PHONETIC_MIDDLE_NAME);
25525dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.phoneticGivenName = c.getString(DisplayNameQuery.PHONETIC_GIVEN_NAME);
25535dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.phoneticNameStyle = c.isNull(DisplayNameQuery.PHONETIC_NAME_STYLE)
25545dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            ? PhoneticNameStyle.UNDEFINED
25555dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            : c.getInt(DisplayNameQuery.PHONETIC_NAME_STYLE);
25565dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    if (!name.isEmpty()) {
25575dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestDisplayNameSource = source;
25585dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestName = name;
25595dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    }
25605dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                } else if (mimeType == mMimeTypeIdOrganization) {
25615dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    mCharArrayBuffer.sizeCopied = 0;
25625dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    c.copyStringToBuffer(DisplayNameQuery.DATA1, mCharArrayBuffer);
25635dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    if (mCharArrayBuffer.sizeCopied != 0) {
2564d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov                        bestDisplayNameSource = source;
25651129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        bestDisplayName = new String(mCharArrayBuffer.data, 0,
25661129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                                mCharArrayBuffer.sizeCopied);
25675dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestPhoneticName = c.getString(DisplayNameQuery.ORGANIZATION_PHONETIC_NAME);
25685dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestPhoneticNameStyle =
25695dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                                c.isNull(DisplayNameQuery.ORGANIZATION_PHONETIC_NAME_STYLE)
25705dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                                    ? PhoneticNameStyle.UNDEFINED
25715dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                                    : c.getInt(DisplayNameQuery.ORGANIZATION_PHONETIC_NAME_STYLE);
25725dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    } else {
25735dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        c.copyStringToBuffer(DisplayNameQuery.TITLE, mCharArrayBuffer);
25745dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        if (mCharArrayBuffer.sizeCopied != 0) {
25751129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                            bestDisplayNameSource = source;
25761129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                            bestDisplayName = new String(mCharArrayBuffer.data, 0,
25771129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                                    mCharArrayBuffer.sizeCopied);
25785dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            bestPhoneticName = null;
25795dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            bestPhoneticNameStyle = PhoneticNameStyle.UNDEFINED;
25801129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        }
2581d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov                    }
25825dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                } else {
25835dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    // Display name is at DATA1 in all other types.
25845dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    // This is ensured in the constructor.
25855dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
25865dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    mCharArrayBuffer.sizeCopied = 0;
25875dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    c.copyStringToBuffer(DisplayNameQuery.DATA1, mCharArrayBuffer);
25885dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    if (mCharArrayBuffer.sizeCopied != 0) {
25895dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestDisplayNameSource = source;
25905dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestDisplayName = new String(mCharArrayBuffer.data, 0,
25915dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                                mCharArrayBuffer.sizeCopied);
25925dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestPhoneticName = null;
25935dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestPhoneticNameStyle = PhoneticNameStyle.UNDEFINED;
25945dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    }
2595d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov                }
2596d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov            }
2597d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
2598d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov        } finally {
2599d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov            c.close();
2600d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov        }
2601d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
26025dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String displayNamePrimary;
26035dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String displayNameAlternative;
26045dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String sortKeyPrimary = null;
26055dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String sortKeyAlternative = null;
26065dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        int displayNameStyle = FullNameStyle.UNDEFINED;
26075dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
26085dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        if (bestDisplayNameSource == DisplayNameSources.STRUCTURED_NAME) {
26095dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            displayNameStyle = bestName.fullNameStyle;
26105dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            if (displayNameStyle == FullNameStyle.CJK
26115dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    || displayNameStyle == FullNameStyle.UNDEFINED) {
26125dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                displayNameStyle = mNameSplitter.getAdjustedFullNameStyle(displayNameStyle);
26135dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                bestName.fullNameStyle = displayNameStyle;
26145dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            }
26155dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
26165dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            displayNamePrimary = mNameSplitter.join(bestName, true);
26175dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            displayNameAlternative = mNameSplitter.join(bestName, false);
26185dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
26195dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            bestPhoneticName = mNameSplitter.joinPhoneticName(bestName);
26205dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            bestPhoneticNameStyle = bestName.phoneticNameStyle;
26215dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        } else {
26225dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            displayNamePrimary = displayNameAlternative = bestDisplayName;
26235dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        }
26245dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
26255dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        if (bestPhoneticName != null) {
26265dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            sortKeyPrimary = sortKeyAlternative = bestPhoneticName;
26275dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            if (bestPhoneticNameStyle == PhoneticNameStyle.UNDEFINED) {
26285dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                bestPhoneticNameStyle = mNameSplitter.guessPhoneticNameStyle(bestPhoneticName);
26295dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            }
26305dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        } else {
26315dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            if (displayNameStyle == FullNameStyle.UNDEFINED) {
26325dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                displayNameStyle = mNameSplitter.guessFullNameStyle(bestDisplayName);
26335dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                if (displayNameStyle == FullNameStyle.UNDEFINED
26345dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        || displayNameStyle == FullNameStyle.CJK) {
26355dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    displayNameStyle = mNameSplitter.getAdjustedNameStyleBasedOnPhoneticNameStyle(
26365dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            displayNameStyle, bestPhoneticNameStyle);
26375dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                }
26385dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                displayNameStyle = mNameSplitter.getAdjustedFullNameStyle(displayNameStyle);
26395dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            }
26405dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            if (displayNameStyle == FullNameStyle.CHINESE) {
26415dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                sortKeyPrimary = sortKeyAlternative =
26424cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                        ContactLocaleUtils.getSortKey(displayNamePrimary, FullNameStyle.CHINESE);
26435dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            }
26445dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        }
26455dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
26465dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        if (sortKeyPrimary == null) {
26475dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            sortKeyPrimary = displayNamePrimary;
26485dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            sortKeyAlternative = displayNameAlternative;
26495dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        }
26505dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
26515dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        setDisplayName(rawContactId, bestDisplayNameSource, displayNamePrimary,
26525dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                displayNameAlternative, bestPhoneticName, bestPhoneticNameStyle,
26535dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                sortKeyPrimary, sortKeyAlternative);
2654d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov    }
2655d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
26561129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private int getDisplayNameSource(int mimeTypeId) {
26571129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        if (mimeTypeId == mMimeTypeIdStructuredName) {
26581129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov            return DisplayNameSources.STRUCTURED_NAME;
26591129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        } else if (mimeTypeId == mMimeTypeIdEmail) {
26601129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov            return DisplayNameSources.EMAIL;
26611129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        } else if (mimeTypeId == mMimeTypeIdPhone) {
26621129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov            return DisplayNameSources.PHONE;
26631129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        } else if (mimeTypeId == mMimeTypeIdOrganization) {
26641129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov            return DisplayNameSources.ORGANIZATION;
26651129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        } else if (mimeTypeId == mMimeTypeIdNickname) {
26661129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov            return DisplayNameSources.NICKNAME;
26671129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        } else {
26681129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov            return DisplayNameSources.UNDEFINED;
26691129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        }
26701129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    }
26711129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov
26729261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /**
267320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     * Delete data row by row so that fixing of primaries etc work correctly.
267420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     */
2675f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana    private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) {
267620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int count = 0;
267720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2678de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
2679de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
268014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, selection, selectionArgs, null);
2681de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        try {
2682de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            while(c.moveToNext()) {
268314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
268414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
2685a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                DataRowHandler rowHandler = getDataRowHandler(mimeType);
2686a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                count += rowHandler.delete(mDb, c);
2687f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                if (!callerIsSyncAdapter) {
268888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                    setRawContactDirty(rawContactId);
2689a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                    if (rowHandler.isAggregationRequired()) {
2690a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                        triggerAggregation(rawContactId);
2691a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                    }
269288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                }
269320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
269420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
2695de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            c.close();
269620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
269720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
269820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        return count;
269920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
270020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
270188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov    /**
270288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     * Delete a data row provided that it is one of the allowed mime types.
270388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     */
270420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    public int deleteData(long dataId, String[] allowedMimeTypes) {
2705f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
270688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
270788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
27084da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(dataId);
27094da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, Data._ID + "=?",
27104da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                mSelectionArgs1, null);
2711f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
271220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        try {
271320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!c.moveToFirst()) {
271420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                return 0;
271520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
271620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
271714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
271820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            boolean valid = false;
271920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            for (int i = 0; i < allowedMimeTypes.length; i++) {
272020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                if (TextUtils.equals(mimeType, allowedMimeTypes[i])) {
272120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    valid = true;
272220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    break;
272320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                }
272420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
272520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
272620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!valid) {
27277a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException("Data type mismatch: expected "
272820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                        + Lists.newArrayList(allowedMimeTypes));
272920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
273020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2731a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            DataRowHandler rowHandler = getDataRowHandler(mimeType);
2732a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            int count = rowHandler.delete(mDb, c);
27338e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
2734a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            if (rowHandler.isAggregationRequired()) {
2735a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                triggerAggregation(rawContactId);
2736a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            }
27378e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            return count;
273820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
273920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            c.close();
274020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
274120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
274220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
274320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    /**
2744ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Inserts an item in the groups table
2745ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
2746f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    private long insertGroup(Uri uri, ContentValues values, boolean callerIsSyncAdapter) {
2747f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.clear();
2748f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.putAll(values);
2749f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
2750e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final Account account = resolveAccount(uri, mValues);
2751ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2752ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Replace package with internal mapping
2753f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        final String packageName = mValues.getAsString(Groups.RES_PACKAGE);
275467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        if (packageName != null) {
2755f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            mValues.put(GroupsColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName));
275667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        }
2757f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.remove(Groups.RES_PACKAGE);
2758ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2759f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (!callerIsSyncAdapter) {
2760f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            mValues.put(Groups.DIRTY, 1);
276173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
276273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
2763f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        long result = mDb.insert(Tables.GROUPS, Groups.TITLE, mValues);
2764ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey
2765f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (mValues.containsKey(Groups.GROUP_VISIBLE)) {
27661a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
2767ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        }
2768ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey
2769ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        return result;
2770ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
2771ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
27725aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private long insertSettings(Uri uri, ContentValues values) {
2773e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final long id = mDb.insert(Tables.SETTINGS, null, values);
27745aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey
27751a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (values.containsKey(Settings.UNGROUPED_VISIBLE)) {
27761a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
2777e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
27781a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey
2779e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return id;
2780e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
2781e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
2782ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
278382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov     * Inserts a status update.
27841f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     */
278582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    public long insertStatusUpdate(ContentValues values) {
278682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        final String handle = values.getAsString(StatusUpdates.IM_HANDLE);
27870a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        final Integer protocol = values.getAsInteger(StatusUpdates.PROTOCOL);
27884dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        String customProtocol = null;
27894dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov
27900a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        if (protocol != null && protocol == Im.PROTOCOL_CUSTOM) {
279182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL);
27924dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            if (TextUtils.isEmpty(customProtocol)) {
27934dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                throw new IllegalArgumentException(
27944dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                        "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM");
27954dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            }
27961f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
27971f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2798dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton        long rawContactId = -1;
2799dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton        long contactId = -1;
280082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        Long dataId = values.getAsLong(StatusUpdates.DATA_ID);
2801f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov        mSb.setLength(0);
2802dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton        if (dataId != null) {
2803dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            // Lookup the contact info for the given data row.
2804dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton
2805f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov            mSb.append(Tables.DATA + "." + Data._ID + "=");
2806f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov            mSb.append(dataId);
28071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } else {
2808dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            // Lookup the data row to attach this presence update to
2809dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton
28100a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            if (TextUtils.isEmpty(handle) || protocol == null) {
28110a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required");
28120a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            }
28130a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
2814dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            // TODO: generalize to allow other providers to match against email
2815dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol;
2816dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton
2817dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            if (matchEmail) {
2818f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov
2819f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                // The following hack forces SQLite to use the (mimetype_id,data1) index, otherwise
2820f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                // the "OR" conjunction confuses it and it switches to a full scan of
2821f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                // the raw_contacts table.
2822f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov
2823f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                // This code relies on the fact that Im.DATA and Email.DATA are in fact the same
2824f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                // column - Data.DATA1
2825f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                mSb.append(DataColumns.MIMETYPE_ID + " IN (")
2826f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(mMimeTypeIdEmail)
2827f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(",")
2828f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(mMimeTypeIdIm)
2829f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(")" + " AND " + Data.DATA1 + "=");
2830f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(mSb, handle);
2831f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                mSb.append(" AND ((" + DataColumns.MIMETYPE_ID + "=")
2832f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(mMimeTypeIdIm)
2833f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(" AND " + Im.PROTOCOL + "=")
2834f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(protocol);
2835dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                if (customProtocol != null) {
2836f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                    mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=");
2837f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                    DatabaseUtils.appendEscapedSQLString(mSb, customProtocol);
2838dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                }
2839f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                mSb.append(") OR (" + DataColumns.MIMETYPE_ID + "=")
2840f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(mMimeTypeIdEmail)
2841f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append("))");
2842dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            } else {
2843f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                mSb.append(DataColumns.MIMETYPE_ID + "=")
2844f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(mMimeTypeIdIm)
2845f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(" AND " + Im.PROTOCOL + "=")
2846f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(protocol)
2847f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                        .append(" AND " + Im.DATA + "=");
2848f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(mSb, handle);
2849dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                if (customProtocol != null) {
2850f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                    mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=");
2851f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                    DatabaseUtils.appendEscapedSQLString(mSb, customProtocol);
2852dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                }
2853dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            }
28541f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
285582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            if (values.containsKey(StatusUpdates.DATA_ID)) {
2856f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                mSb.append(" AND " + DataColumns.CONCRETE_ID + "=")
285782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                        .append(values.getAsLong(StatusUpdates.DATA_ID));
2858dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            }
285970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
2860f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov        mSb.append(" AND ").append(getContactsRestrictions());
286170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
28621f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        Cursor cursor = null;
28631f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        try {
2864de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION,
2865c03e723e7b07434a3e60454606bc18e2df4ee06bDmitri Plotnikov                    mSb.toString(), null, null, null,
2866c03e723e7b07434a3e60454606bc18e2df4ee06bDmitri Plotnikov                    Contacts.IN_VISIBLE_GROUP + " DESC, " + Data.RAW_CONTACT_ID);
28671f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            if (cursor.moveToFirst()) {
286867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                dataId = cursor.getLong(DataContactsQuery.DATA_ID);
28695ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID);
2870e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                contactId = cursor.getLong(DataContactsQuery.CONTACT_ID);
28711f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            } else {
28721f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                // No contact found, return a null URI
28731f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                return -1;
28741f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
28751f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } finally {
287631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            if (cursor != null) {
287731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                cursor.close();
287831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
28791f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
28801f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
288182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        if (values.containsKey(StatusUpdates.PRESENCE)) {
2882a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            if (customProtocol == null) {
2883a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                // We cannot allow a null in the custom protocol field, because SQLite3 does not
2884a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                // properly enforce uniqueness of null values
2885a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                customProtocol = "";
2886a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            }
2887a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
2888a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mValues.clear();
288982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.DATA_ID, dataId);
2890a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId);
2891a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mValues.put(PresenceColumns.CONTACT_ID, contactId);
289282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.PROTOCOL, protocol);
289382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol);
289482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.IM_HANDLE, handle);
289582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            if (values.containsKey(StatusUpdates.IM_ACCOUNT)) {
289682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT));
2897a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            }
289882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.PRESENCE,
289982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                    values.getAsString(StatusUpdates.PRESENCE));
29001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2901a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            // Insert the presence update
2902a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mDb.replace(Tables.PRESENCE, null, mValues);
2903a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        }
2904e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
29050a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
290682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        if (values.containsKey(StatusUpdates.STATUS)) {
290782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            String status = values.getAsString(StatusUpdates.STATUS);
29080a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            String resPackage = values.getAsString(StatusUpdates.STATUS_RES_PACKAGE);
29090a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            Integer labelResource = values.getAsInteger(StatusUpdates.STATUS_LABEL);
29100a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
29110a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            if (TextUtils.isEmpty(resPackage)
29120a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                    && (labelResource == null || labelResource == 0)
29130a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                    && protocol != null) {
29140a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                labelResource = Im.getProtocolLabelResource(protocol);
29150a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            }
29160a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
29170a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            Long iconResource = values.getAsLong(StatusUpdates.STATUS_ICON);
29180a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            // TODO compute the default icon based on the protocol
29190a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
2920a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            if (TextUtils.isEmpty(status)) {
2921a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                mStatusUpdateDelete.bindLong(1, dataId);
2922a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                mStatusUpdateDelete.execute();
292382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            } else if (values.containsKey(StatusUpdates.STATUS_TIMESTAMP)) {
292482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP);
2925a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                mStatusUpdateReplace.bindLong(1, dataId);
2926a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                mStatusUpdateReplace.bindLong(2, timestamp);
29275dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                bindString(mStatusUpdateReplace, 3, status);
29285dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                bindString(mStatusUpdateReplace, 4, resPackage);
29295dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                bindLong(mStatusUpdateReplace, 5, iconResource);
29305dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                bindLong(mStatusUpdateReplace, 6, labelResource);
2931a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                mStatusUpdateReplace.execute();
2932a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            } else {
2933a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
2934a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                try {
2935a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateInsert.bindLong(1, dataId);
29365dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    bindString(mStatusUpdateInsert, 2, status);
29375dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    bindString(mStatusUpdateInsert, 3, resPackage);
29385dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    bindLong(mStatusUpdateInsert, 4, iconResource);
29395dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    bindLong(mStatusUpdateInsert, 5, labelResource);
2940a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateInsert.executeInsert();
2941a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                } catch (SQLiteConstraintException e) {
2942a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    // The row already exists - update it
29430a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                    long timestamp = System.currentTimeMillis();
2944a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateAutoTimestamp.bindLong(1, timestamp);
29455dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    bindString(mStatusUpdateAutoTimestamp, 2, status);
2946a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateAutoTimestamp.bindLong(3, dataId);
29475dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    bindString(mStatusUpdateAutoTimestamp, 4, status);
2948a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateAutoTimestamp.execute();
29490a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
29505dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    bindString(mStatusAttributionUpdate, 1, resPackage);
29515dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    bindLong(mStatusAttributionUpdate, 2, iconResource);
29525dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    bindLong(mStatusAttributionUpdate, 3, labelResource);
29530a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                    mStatusAttributionUpdate.bindLong(4, dataId);
29540a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                    mStatusAttributionUpdate.execute();
2955a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                }
2956e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            }
2957e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        }
2958bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov
2959a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        if (contactId != -1) {
2960a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mLastStatusUpdate.bindLong(1, contactId);
2961a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mLastStatusUpdate.bindLong(2, contactId);
2962a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mLastStatusUpdate.execute();
2963a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        }
2964a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
2965a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        return dataId;
29661f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    }
29671f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
29684f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
2969de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
2970bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
2971b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "deleteInTransaction: " + uri);
2972b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2973b5a4add17815167d20a90645779df34cdf45280dFred Quintana        flushTransactionalChanges();
2974f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        final boolean callerIsSyncAdapter =
2975f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false);
2976508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        final int match = sUriMatcher.match(uri);
2977508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        switch (match) {
297835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
2979b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getSyncState().delete(mDb, selection, selectionArgs);
298035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2981b5a4add17815167d20a90645779df34cdf45280dFred Quintana            case SYNCSTATE_ID:
2982b5a4add17815167d20a90645779df34cdf45280dFred Quintana                String selectionWithId =
2983b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ")
2984b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        + (selection == null ? "" : " AND (" + selection + ")");
2985b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getSyncState().delete(mDb, selectionWithId, selectionArgs);
2986b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2987cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            case CONTACTS: {
2988cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                // TODO
2989cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                return 0;
2990cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            }
2991cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
2992d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
2993d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
2994cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                return deleteContact(contactId);
29956bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
29966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
29972e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            case CONTACTS_LOOKUP:
29982e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            case CONTACTS_LOOKUP_ID: {
29992e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final List<String> pathSegments = uri.getPathSegments();
30002e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final int segmentCount = pathSegments.size();
30012e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                if (segmentCount < 3) {
30022e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                    throw new IllegalArgumentException("URI " + uri + " is missing a lookup key");
30032e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                }
30042e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final String lookupKey = pathSegments.get(2);
30052e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final long contactId = lookupContactIdByLookupKey(mDb, lookupKey);
30062e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                return deleteContact(contactId);
30072e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            }
30082e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey
30092971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            case RAW_CONTACTS: {
30102971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                int numDeletes = 0;
3011fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                Cursor c = mDb.query(Tables.RAW_CONTACTS,
3012fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        new String[]{RawContacts._ID, RawContacts.CONTACT_ID},
3013e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs, null, null, null);
30142971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                try {
30152971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    while (c.moveToNext()) {
30162971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        final long rawContactId = c.getLong(0);
3017fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        long contactId = c.getLong(1);
3018fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        numDeletes += deleteRawContact(rawContactId, contactId,
3019fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                                callerIsSyncAdapter);
30202971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    }
30212971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                } finally {
30222971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    c.close();
30232971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                }
30242971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return numDeletes;
30252971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            }
30262971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana
30275ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
30282971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                final long rawContactId = ContentUris.parseId(uri);
3029fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                return deleteRawContact(rawContactId, mDbHelper.getContactId(rawContactId),
3030fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        callerIsSyncAdapter);
3031508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
3032508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
303320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
3034f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
3035944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                return deleteData(appendAccountToSelection(uri, selection), selectionArgs,
3036f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                        callerIsSyncAdapter);
303720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
303820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
303948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case DATA_ID:
304048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID:
304148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID:
304248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID: {
3043508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey                long dataId = ContentUris.parseId(uri);
3044f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
30454da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                mSelectionArgs1[0] = String.valueOf(dataId);
30464da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                return deleteData(Data._ID + "=?", mSelectionArgs1, callerIsSyncAdapter);
3047ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
3048ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3049ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
3050f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
30515aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter);
30522971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            }
30532971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana
30542971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            case GROUPS: {
30552971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                int numDeletes = 0;
30562971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups._ID},
3057e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs, null, null, null);
30582971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                try {
30592971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    while (c.moveToNext()) {
30605aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                        numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter);
30612971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    }
30622971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                } finally {
30632971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    c.close();
30642971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                }
306581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (numDeletes > 0) {
3066f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
306781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
30682971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return numDeletes;
3069508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
3070508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
3071eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
307243880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov                mSyncToNetwork |= !callerIsSyncAdapter;
3073e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                return deleteSettings(uri, appendAccountToSelection(uri, selection), selectionArgs);
3074eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
3075eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
307682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES: {
30770a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                return deleteStatusUpdates(selection, selectionArgs);
30781f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
30791f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
308081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            default: {
308181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                mSyncToNetwork = true;
30823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                return mLegacyApiSupport.delete(uri, selection, selectionArgs);
308381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            }
3084508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        }
30854f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
30864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
30871c8e40c18f92722b9bec6e8ce2e345a9828efa16Dmitri Plotnikov    public int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) {
3088ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        mGroupIdCache.clear();
3089b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        final long groupMembershipMimetypeId = mDbHelper
309094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
3091de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mDb.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "="
309294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "="
309394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupId, null);
309494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
309594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        try {
3096f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            if (callerIsSyncAdapter) {
3097de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null);
309894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            } else {
309994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.clear();
310094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.put(Groups.DELETED, 1);
3101f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mValues.put(Groups.DIRTY, 1);
3102de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, null);
310394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            }
310494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        } finally {
31051a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
310694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
310794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
310894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
31095aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private int deleteSettings(Uri uri, String selection, String[] selectionArgs) {
3110e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final int count = mDb.delete(Tables.SETTINGS, selection, selectionArgs);
31111a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        mVisibleTouched = true;
3112e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return count;
3113e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
3114e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
3115cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov    private int deleteContact(long contactId) {
3116cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        Cursor c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID},
3117cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                RawContacts.CONTACT_ID + "=" + contactId, null, null, null, null);
3118cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        try {
3119cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            while (c.moveToNext()) {
3120cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                long rawContactId = c.getLong(0);
3121cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                markRawContactAsDeleted(rawContactId);
3122cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            }
3123cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        } finally {
3124cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            c.close();
3125cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        }
3126cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
3127cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        return mDb.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null);
3128cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov    }
3129cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
3130fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov    public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) {
31313389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov        mContactAggregator.invalidateAggregationExceptionCache();
3132f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (callerIsSyncAdapter) {
313314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mDb.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null);
3134fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov            int count = mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null);
3135fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov            mContactAggregator.updateDisplayNameForContact(mDb, contactId);
3136fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov            return count;
313733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        } else {
3138b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            mDbHelper.removeContactIfSingleton(rawContactId);
3139cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            return markRawContactAsDeleted(rawContactId);
314033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        }
314133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
314233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
31430a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov    private int deleteStatusUpdates(String selection, String[] selectionArgs) {
31449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      // delete from both tables: presence and status_updates
31459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      // TODO should account type/name be appended to the where clause?
31469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      if (VERBOSE_LOGGING) {
31479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori          Log.v(TAG, "deleting data from status_updates for " + selection);
31489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      }
31499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      mDb.delete(Tables.STATUS_UPDATES, getWhereClauseForStatusUpdatesTable(selection),
31509705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori          selectionArgs);
31519705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      return mDb.delete(Tables.PRESENCE, selection, selectionArgs);
31520a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov    }
31530a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
3154cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov    private int markRawContactAsDeleted(long rawContactId) {
315581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        mSyncToNetwork = true;
315681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov
3157cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.clear();
3158cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContacts.DELETED, 1);
3159cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
3160cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1);
3161cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.putNull(RawContacts.CONTACT_ID);
3162cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContacts.DIRTY, 1);
3163cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        return updateRawContact(rawContactId, mValues);
3164cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov    }
3165cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
31664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
3167de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int updateInTransaction(Uri uri, ContentValues values, String selection,
3168de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            String[] selectionArgs) {
3169bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
3170b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "updateInTransaction: " + uri);
3171b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
3172b5a4add17815167d20a90645779df34cdf45280dFred Quintana
317335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        int count = 0;
317400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
317500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        final int match = sUriMatcher.match(uri);
3176b5a4add17815167d20a90645779df34cdf45280dFred Quintana        if (match == SYNCSTATE_ID && selection == null) {
3177b5a4add17815167d20a90645779df34cdf45280dFred Quintana            long rowId = ContentUris.parseId(uri);
31781129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov            Object data = values.get(ContactsContract.SyncState.DATA);
3179b5a4add17815167d20a90645779df34cdf45280dFred Quintana            mUpdatedSyncStates.put(rowId, data);
3180b5a4add17815167d20a90645779df34cdf45280dFred Quintana            return 1;
3181b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
3182b5a4add17815167d20a90645779df34cdf45280dFred Quintana        flushTransactionalChanges();
3183f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        final boolean callerIsSyncAdapter =
3184f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false);
318500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        switch(match) {
318635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
3187b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getSyncState().update(mDb, values,
3188b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        appendAccountToSelection(uri, selection), selectionArgs);
3189b5a4add17815167d20a90645779df34cdf45280dFred Quintana
3190b5a4add17815167d20a90645779df34cdf45280dFred Quintana            case SYNCSTATE_ID: {
3191b5a4add17815167d20a90645779df34cdf45280dFred Quintana                selection = appendAccountToSelection(uri, selection);
3192b5a4add17815167d20a90645779df34cdf45280dFred Quintana                String selectionWithId =
3193b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ")
3194b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        + (selection == null ? "" : " AND (" + selection + ")");
3195b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getSyncState().update(mDb, values,
3196b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        selectionWithId, selectionArgs);
3197b5a4add17815167d20a90645779df34cdf45280dFred Quintana            }
319835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
3199d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
32008c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                count = updateContactOptions(values, selection, selectionArgs);
320100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
320200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
320300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
3204d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
32058c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                count = updateContactOptions(ContentUris.parseId(uri), values);
3206c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                break;
3207c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar            }
3208c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
32092e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            case CONTACTS_LOOKUP:
32102e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            case CONTACTS_LOOKUP_ID: {
32112e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final List<String> pathSegments = uri.getPathSegments();
32122e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final int segmentCount = pathSegments.size();
32132e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                if (segmentCount < 3) {
32142e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                    throw new IllegalArgumentException("URI " + uri + " is missing a lookup key");
32152e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                }
32162e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final String lookupKey = pathSegments.get(2);
32172e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final long contactId = lookupContactIdByLookupKey(mDb, lookupKey);
32188c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                count = updateContactOptions(contactId, values);
32192e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                break;
32202e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            }
32212e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey
32227d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh            case RAW_CONTACTS_DATA: {
32237d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                final String rawContactId = uri.getPathSegments().get(1);
32247d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ")
32257d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                    + (selection == null ? "" : " AND " + selection);
32267d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh
32277d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter);
32287d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh
32297d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                break;
32307d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh            }
32317d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh
323220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
3233944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                count = updateData(uri, values, appendAccountToSelection(uri, selection),
3234f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                        selectionArgs, callerIsSyncAdapter);
323581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
3236f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
323781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
323820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                break;
323920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
3240c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
324148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case DATA_ID:
324248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID:
324348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID:
324448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID: {
3245f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter);
324681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
3247f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
324881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
324900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
325000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
32517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32525ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
32535ac5c70d1165309302ebcc931f51723e37d31e0bJeff Sharkey                selection = appendAccountToSelection(uri, selection);
32544529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                count = updateRawContacts(values, selection, selectionArgs);
32557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
32567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
32577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32585ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
325933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
32604529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                if (selection != null) {
32614da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId));
32624da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    count = updateRawContacts(values, RawContacts._ID + "=?"
32634529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                                    + " AND(" + selection + ")", selectionArgs);
32644529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                } else {
32654da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    mSelectionArgs1[0] = String.valueOf(rawContactId);
32664da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    count = updateRawContacts(values, RawContacts._ID + "=?", mSelectionArgs1);
32674529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                }
32687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
32697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
32707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
3271ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
32725aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                count = updateGroups(uri, values, appendAccountToSelection(uri, selection),
3273f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                        selectionArgs, callerIsSyncAdapter);
327481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
3275f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
327681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
3277ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
3278ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
3279ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3280ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
3281ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
32824da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(groupId));
32834da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                String selectionWithId = Groups._ID + "=? "
328473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        + (selection == null ? "" : " AND " + selection);
32855aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                count = updateGroups(uri, values, selectionWithId, selectionArgs,
32865aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                        callerIsSyncAdapter);
328781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
3288f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
328981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
3290ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
3291ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
3292ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3293127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
3294de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateAggregationException(mDb, values);
3295b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
3296b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
3297b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
3298eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
3299e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                count = updateSettings(uri, values, appendAccountToSelection(uri, selection),
3300e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                        selectionArgs);
330143880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov                mSyncToNetwork |= !callerIsSyncAdapter;
3302eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
3303eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
3304eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
33059705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            case STATUS_UPDATES: {
33069705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                count = updateStatusUpdate(uri, values, selection, selectionArgs);
33079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                break;
33089705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            }
33099705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
331081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            default: {
331181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                mSyncToNetwork = true;
3312f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.update(uri, values, selection, selectionArgs);
331381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            }
331400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        }
331500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
331600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        return count;
33174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
33184f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
33199705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    private int updateStatusUpdate(Uri uri, ContentValues values, String selection,
33209705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        String[] selectionArgs) {
33219705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        // update status_updates table, if status is provided
33229705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        // TODO should account type/name be appended to the where clause?
33239705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        int updateCount = 0;
33249705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContentValues settableValues = getSettableColumnsForStatusUpdatesTable(values);
33259705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        if (settableValues.size() > 0) {
33269705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori          updateCount = mDb.update(Tables.STATUS_UPDATES,
33279705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                    settableValues,
33289705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                    getWhereClauseForStatusUpdatesTable(selection),
33299705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                    selectionArgs);
33309705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        }
33319705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
33329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        // now update the Presence table
33339705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        settableValues = getSettableColumnsForPresenceTable(values);
33349705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        if (settableValues.size() > 0) {
33359705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori          updateCount = mDb.update(Tables.PRESENCE, settableValues,
33369705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                    selection, selectionArgs);
33379705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        }
33389705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        // TODO updateCount is not entirely a valid count of updated rows because 2 tables could
33399705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        // potentially get updated in this method.
33409705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        return updateCount;
33419705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    }
33429705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
33439705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    /**
33449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori     * Build a where clause to select the rows to be updated in status_updates table.
33459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori     */
33469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    private String getWhereClauseForStatusUpdatesTable(String selection) {
33479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mSb.setLength(0);
33489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mSb.append(WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE);
33499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mSb.append(selection);
33509705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mSb.append(")");
33519705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        return mSb.toString();
33529705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    }
33539705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
33549705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    private ContentValues getSettableColumnsForStatusUpdatesTable(ContentValues values) {
33559705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mValues.clear();
33569705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS, values,
33579705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.STATUS);
33589705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_TIMESTAMP, values,
33599705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.STATUS_TIMESTAMP);
33609705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_RES_PACKAGE, values,
33619705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.STATUS_RES_PACKAGE);
33629705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_LABEL, values,
33639705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.STATUS_LABEL);
33649705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_ICON, values,
33659705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.STATUS_ICON);
33669705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        return mValues;
33679705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    }
33689705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
33699705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    private ContentValues getSettableColumnsForPresenceTable(ContentValues values) {
33709705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mValues.clear();
33719705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.PRESENCE, values,
33729705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.PRESENCE);
33739705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        return mValues;
33749705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    }
33759705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
33765aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private int updateGroups(Uri uri, ContentValues values, String selectionWithId,
3377f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            String[] selectionArgs, boolean callerIsSyncAdapter) {
337873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
3379ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        mGroupIdCache.clear();
3380ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
338173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        ContentValues updatedValues;
3382f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (!callerIsSyncAdapter && !values.containsKey(Groups.DIRTY)) {
338373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = mValues;
338473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.clear();
338573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.putAll(values);
338673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.put(Groups.DIRTY, 1);
338773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        } else {
338873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = values;
338973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
339073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
3391ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        int count = mDb.update(Tables.GROUPS, updatedValues, selectionWithId, selectionArgs);
33921a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) {
33931a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
339494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
33956ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi        if (updatedValues.containsKey(Groups.SHOULD_SYNC)
33961129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                && updatedValues.getAsInteger(Groups.SHOULD_SYNC) != 0) {
33976ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups.ACCOUNT_NAME,
3398e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                    Groups.ACCOUNT_TYPE}, selectionWithId, selectionArgs, null,
33996ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                    null, null);
34006ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            String accountName;
34016ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            String accountType;
34026ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            try {
34036ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                while (c.moveToNext()) {
34046ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                    accountName = c.getString(0);
34056ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                    accountType = c.getString(1);
34066ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                    if(!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
34076ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                        Account account = new Account(accountName, accountType);
3408ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                        ContentResolver.requestSync(account, ContactsContract.AUTHORITY,
34096ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                                new Bundle());
34106ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                        break;
34116ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                    }
34126ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                }
34136ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            } finally {
34146ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                c.close();
34156ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            }
34166ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi        }
341794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        return count;
341894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
341994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
3420b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov    private int updateSettings(Uri uri, ContentValues values, String selection,
3421b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            String[] selectionArgs) {
3422e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final int count = mDb.update(Tables.SETTINGS, values, selection, selectionArgs);
34231a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (values.containsKey(Settings.UNGROUPED_VISIBLE)) {
34241a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
3425e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
3426e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return count;
3427e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
3428e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
34294529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov    private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs) {
34304529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        if (values.containsKey(RawContacts.CONTACT_ID)) {
34314529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " +
34324529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                    "in content values. Contact IDs are assigned automatically");
34334529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        }
343473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
34354529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        int count = 0;
3436b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        Cursor cursor = mDb.query(mDbHelper.getRawContactView(),
343751bf5ea9531b9da72caff607dbdf35fd6f61cbe2Jeff Sharkey                new String[] { RawContacts._ID }, selection,
34384529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                selectionArgs, null, null, null);
34394529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        try {
34404529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            while (cursor.moveToNext()) {
34414529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                long rawContactId = cursor.getLong(0);
34424529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                updateRawContact(rawContactId, values);
34434529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                count++;
34444529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            }
34454529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        } finally {
34464529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            cursor.close();
34474529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        }
34484529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov
34494529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        return count;
34504529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov    }
34514529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov
34524529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov    private int updateRawContact(long rawContactId, ContentValues values) {
345319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        final String selection = RawContacts._ID + " = " + rawContactId;
345419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED)
345519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                && values.getAsInteger(RawContacts.DELETED) == 0);
345619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        int previousDeleted = 0;
3457ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        String accountType = null;
3458ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        String accountName = null;
345919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        if (requestUndoDelete) {
346019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            Cursor cursor = mDb.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, selection,
346119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                    null, null, null, null);
346219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            try {
346319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                if (cursor.moveToFirst()) {
346419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                    previousDeleted = cursor.getInt(RawContactsQuery.DELETED);
3465ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    accountType = cursor.getString(RawContactsQuery.ACCOUNT_TYPE);
3466ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    accountName = cursor.getString(RawContactsQuery.ACCOUNT_NAME);
346719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                }
346819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            } finally {
346919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                cursor.close();
347019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            }
347119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            values.put(ContactsContract.RawContacts.AGGREGATION_MODE,
347219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                    ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT);
347319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        }
3474f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov
347519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        int count = mDb.update(Tables.RAW_CONTACTS, values, selection, null);
34765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (count != 0) {
3477433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey            if (values.containsKey(RawContacts.STARRED)) {
34784529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                mContactAggregator.updateStarred(rawContactId);
3479433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey            }
3480285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            if (values.containsKey(RawContacts.SOURCE_ID)) {
34812b7a632bba423357ae5641f94da6a2f71afc523bDmitri Plotnikov                mContactAggregator.updateLookupKeyForRawContact(mDb, rawContactId);
3482285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
3483f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov            if (values.containsKey(RawContacts.NAME_VERIFIED)) {
3484f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov
3485f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                // If setting NAME_VERIFIED for this raw contact, reset it for all
3486f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                // other raw contacts in the same aggregate
3487f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                if (values.getAsInteger(RawContacts.NAME_VERIFIED) != 0) {
3488f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                    mResetNameVerifiedForOtherRawContacts.bindLong(1, rawContactId);
3489f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                    mResetNameVerifiedForOtherRawContacts.bindLong(2, rawContactId);
3490f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                    mResetNameVerifiedForOtherRawContacts.execute();
3491f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                }
3492f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                mContactAggregator.updateDisplayNameForRawContact(mDb, rawContactId);
3493f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov            }
349419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            if (requestUndoDelete && previousDeleted == 1) {
349519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                // undo delete, needs aggregation again.
3496ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                mInsertedRawContacts.put(rawContactId, new Account(accountName, accountType));
349719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            }
34985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
34995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return count;
350033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
350133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
3502321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    private int updateData(Uri uri, ContentValues values, String selection,
3503f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            String[] selectionArgs, boolean callerIsSyncAdapter) {
350420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.clear();
350520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.putAll(values);
350620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data._ID);
35075ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mValues.remove(Data.RAW_CONTACT_ID);
350820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
350920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
351020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        String packageName = values.getAsString(Data.RES_PACKAGE);
351120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        if (packageName != null) {
351220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.remove(Data.RES_PACKAGE);
3513b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName));
351420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
351520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
351670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsSuperPrimary = mValues.containsKey(Data.IS_SUPER_PRIMARY);
351770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsPrimary = mValues.containsKey(Data.IS_PRIMARY);
351820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
351920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // Remove primary or super primary values being set to 0. This is disallowed by the
352020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // content provider.
352170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsSuperPrimary && mValues.getAsInteger(Data.IS_SUPER_PRIMARY) == 0) {
352220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsSuperPrimary = false;
352370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_SUPER_PRIMARY);
352420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
352570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsPrimary && mValues.getAsInteger(Data.IS_PRIMARY) == 0) {
352620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsPrimary = false;
352770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_PRIMARY);
352820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
352920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
3530653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        int count = 0;
353120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
3532653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
3533653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        // so we don't need to worry about updating data we don't have permission to read.
353414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(uri, DataUpdateQuery.COLUMNS, selection, selectionArgs, null);
3535653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        try {
3536653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            while(c.moveToNext()) {
3537f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                count += updateData(mValues, c, callerIsSyncAdapter);
353820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
3539653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        } finally {
3540653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            c.close();
354120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
354220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
3543653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        return count;
354420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
354520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
3546f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana    private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) {
3547653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        if (values.size() == 0) {
3548653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return 0;
3549321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        }
3550653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
355114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        final String mimeType = c.getString(DataUpdateQuery.MIMETYPE);
3552a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        DataRowHandler rowHandler = getDataRowHandler(mimeType);
3553f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        rowHandler.update(mDb, values, c, callerIsSyncAdapter);
35548e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
3555a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        if (rowHandler.isAggregationRequired()) {
3556a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            triggerAggregation(rawContactId);
3557a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
35588e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
3559653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        return 1;
3560321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    }
3561321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana
35628c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov    private int updateContactOptions(ContentValues values, String selection,
35638c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            String[] selectionArgs) {
35648c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        int count = 0;
3565b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        Cursor cursor = mDb.query(mDbHelper.getContactView(),
35668c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                new String[] { Contacts._ID }, selection,
35678c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                selectionArgs, null, null, null);
35688c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        try {
35698c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            while (cursor.moveToNext()) {
35708c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                long contactId = cursor.getLong(0);
35718c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                updateContactOptions(contactId, values);
35728c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                count++;
35738c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            }
35748c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        } finally {
35758c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            cursor.close();
35768c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        }
35778c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
35788c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        return count;
35798c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov    }
35808c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
35818c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov    private int updateContactOptions(long contactId, ContentValues values) {
3582d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
35838c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        mValues.clear();
3584b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE,
3585d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.CUSTOM_RINGTONE);
3586b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL,
3587d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.SEND_TO_VOICEMAIL);
3588b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED,
3589d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.LAST_TIME_CONTACTED);
3590b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED,
3591d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.TIMES_CONTACTED);
3592b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED,
3593d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.STARRED);
3594d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
3595d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // Nothing to update - just return
35968c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        if (mValues.size() == 0) {
3597d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov            return 0;
3598d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        }
3599d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
36008c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        if (mValues.containsKey(RawContacts.STARRED)) {
3601c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey            // Mark dirty when changing starred to trigger sync
36028c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            mValues.put(RawContacts.DIRTY, 1);
3603c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey        }
3604c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey
36054da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(contactId);
36064da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov        mDb.update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=?", mSelectionArgs1);
36078c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
36088c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        // Copy changeable values to prevent automatically managed fields from
36098c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        // being explicitly updated by clients.
36108c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        mValues.clear();
3611b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE,
36128c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.CUSTOM_RINGTONE);
3613b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL,
36148c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.SEND_TO_VOICEMAIL);
3615b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED,
36168c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.LAST_TIME_CONTACTED);
3617b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED,
36188c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.TIMES_CONTACTED);
3619b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED,
36208c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.STARRED);
36218c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
36229b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori        int rslt = mDb.update(Tables.CONTACTS, mValues, Contacts._ID + "=?", mSelectionArgs1);
36236e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori
36249b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori        if (values.containsKey(Contacts.LAST_TIME_CONTACTED) &&
36259b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori                !values.containsKey(Contacts.TIMES_CONTACTED)) {
36269b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1);
36279b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1);
36289b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori        }
36299b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori        return rslt;
3630f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
3631d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
3632127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov    private int updateAggregationException(SQLiteDatabase db, ContentValues values) {
3633127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        int exceptionType = values.getAsInteger(AggregationExceptions.TYPE);
36340c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1);
36350c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2);
363680c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
36370c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        long rawContactId1, rawContactId2;
36380c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        if (rcId1 < rcId2) {
36390c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId1 = rcId1;
36400c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId2 = rcId2;
36410c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        } else {
36420c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId2 = rcId1;
36430c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId1 = rcId2;
3644b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        }
3645127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
36460c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) {
36474da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs2[0] = String.valueOf(rawContactId1);
36484da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs2[1] = String.valueOf(rawContactId2);
36490c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            db.delete(Tables.AGGREGATION_EXCEPTIONS,
36504da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    AggregationExceptions.RAW_CONTACT_ID1 + "=? AND "
36514da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    + AggregationExceptions.RAW_CONTACT_ID2 + "=?", mSelectionArgs2);
36520c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        } else {
36536bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov            ContentValues exceptionValues = new ContentValues(3);
36546bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov            exceptionValues.put(AggregationExceptions.TYPE, exceptionType);
36550c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
36560c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
36570c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID,
36580c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov                    exceptionValues);
3659127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        }
3660127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
36613389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov        mContactAggregator.invalidateAggregationExceptionCache();
3662dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov        mContactAggregator.markForAggregation(rawContactId1);
3663dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov        mContactAggregator.markForAggregation(rawContactId2);
3664dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov
3665b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        long contactId1 = mDbHelper.getContactId(rawContactId1);
36660c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        mContactAggregator.aggregateContact(db, rawContactId1, contactId1);
36670c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov
3668b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        long contactId2 = mDbHelper.getContactId(rawContactId2);
36690c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        mContactAggregator.aggregateContact(db, rawContactId2, contactId2);
3670127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
3671127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // The return value is fake - we just confirm that we made a change, not count actual
3672127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // rows changed.
3673127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        return 1;
3674b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    }
3675b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
367670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong    public void onAccountsUpdated(Account[] accounts) {
3677b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        mDb = mDbHelper.getWritableDatabase();
367870d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        if (mDb == null) return;
367970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong
3680627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        HashSet<Account> existingAccounts = new HashSet<Account>();
3681627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        boolean hasUnassignedContacts[] = new boolean[]{false};
368270d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        mDb.beginTransaction();
368370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        try {
3684627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            findValidAccounts(existingAccounts, hasUnassignedContacts,
3685627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    Tables.RAW_CONTACTS, RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_TYPE);
3686627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            findValidAccounts(existingAccounts, hasUnassignedContacts,
3687627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    Tables.GROUPS, Groups.ACCOUNT_NAME, Groups.ACCOUNT_TYPE);
3688627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            findValidAccounts(existingAccounts, hasUnassignedContacts,
3689627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    Tables.SETTINGS, Settings.ACCOUNT_NAME, Settings.ACCOUNT_TYPE);
369048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
3691627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            // Remove all valid accounts from the existing account set. What is left
3692627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            // in the existingAccounts set will be extra accounts whose data must be deleted.
3693627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            HashSet<Account> accountsToDelete = new HashSet<Account>(existingAccounts);
3694627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            for (Account account : accounts) {
3695627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                accountsToDelete.remove(account);
369670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            }
369770d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong
369870d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            for (Account account : accountsToDelete) {
36995f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                Log.d(TAG, "removing data for removed account " + account);
3700627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                String[] params = new String[] {account.name, account.type};
3701627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                mDb.execSQL(
3702627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        "DELETE FROM " + Tables.GROUPS +
3703627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        " WHERE " + Groups.ACCOUNT_NAME + " = ?" +
3704627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                                " AND " + Groups.ACCOUNT_TYPE + " = ?", params);
3705627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                mDb.execSQL(
3706627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        "DELETE FROM " + Tables.PRESENCE +
3707627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (" +
3708627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                                "SELECT " + RawContacts._ID +
3709627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                                " FROM " + Tables.RAW_CONTACTS +
3710627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                                " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" +
3711627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                                " AND " + RawContacts.ACCOUNT_TYPE + " = ?)", params);
3712627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                mDb.execSQL(
3713627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        "DELETE FROM " + Tables.RAW_CONTACTS +
3714627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" +
3715627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        " AND " + RawContacts.ACCOUNT_TYPE + " = ?", params);
3716627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                mDb.execSQL(
3717627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        "DELETE FROM " + Tables.SETTINGS +
3718627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        " WHERE " + Settings.ACCOUNT_NAME + " = ?" +
3719627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        " AND " + Settings.ACCOUNT_TYPE + " = ?", params);
3720627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            }
3721627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov
3722627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            if (hasUnassignedContacts[0]) {
3723627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov
3724627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                Account primaryAccount = null;
3725627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                for (Account account : accounts) {
3726627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    if (isWritableAccount(account)) {
3727627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        primaryAccount = account;
3728627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        break;
3729627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    }
3730627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                }
3731627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov
3732627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                if (primaryAccount != null) {
3733627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    String[] params = new String[] {primaryAccount.name, primaryAccount.type};
3734627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov
3735627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    mDb.execSQL(
3736627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                            "UPDATE " + Tables.RAW_CONTACTS +
3737627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                            " SET " + RawContacts.ACCOUNT_NAME + "=?,"
3738627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                                    + RawContacts.ACCOUNT_TYPE + "=?" +
3739627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                            " WHERE " + RawContacts.ACCOUNT_NAME + " IS NULL" +
3740627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                            " AND " + RawContacts.ACCOUNT_TYPE + " IS NULL", params);
3741627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov
3742627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    // We don't currently support groups for unsynced accounts, so this is for
3743627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    // the future
3744627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    mDb.execSQL(
3745627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                            "UPDATE " + Tables.GROUPS +
3746627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                            " SET " + Groups.ACCOUNT_NAME + "=?,"
3747627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                                    + Groups.ACCOUNT_TYPE + "=?" +
3748627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                            " WHERE " + Groups.ACCOUNT_NAME + " IS NULL" +
3749627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                            " AND " + Groups.ACCOUNT_TYPE + " IS NULL", params);
3750627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                }
375170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            }
3752627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov
3753b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            mDbHelper.getSyncState().onAccountsChanged(mDb, accounts);
375470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            mDb.setTransactionSuccessful();
375570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        } finally {
375670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            mDb.endTransaction();
375770d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        }
375870d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong    }
3759619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
3760619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
3761627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov     * Finds all distinct accounts present in the specified table.
3762627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov     */
3763627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov    private void findValidAccounts(Set<Account> validAccounts, boolean[] hasUnassignedContacts,
3764627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            String table, String accountNameColumn, String accountTypeColumn) {
3765627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        Cursor c = mDb.rawQuery("SELECT DISTINCT " + accountNameColumn + "," + accountTypeColumn
3766627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                + " FROM " + table, null);
3767627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        try {
3768627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            while (c.moveToNext()) {
3769627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                if (c.isNull(0) && c.isNull(1)) {
3770627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    hasUnassignedContacts[0] = true;
3771627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                } else {
3772627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    validAccounts.add(new Account(c.getString(0), c.getString(1)));
3773627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                }
3774627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            }
3775627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        } finally {
3776627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            c.close();
3777627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        }
3778627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov    }
3779627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov
3780627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov    /**
3781622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey     * Test all against {@link TextUtils#isEmpty(CharSequence)}.
3782622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey     */
378367c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov    private static boolean areAllEmpty(ContentValues values, String[] keys) {
378467c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov        for (String key : keys) {
378567c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            if (!TextUtils.isEmpty(values.getAsString(key))) {
378667c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                return false;
378767c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            }
378867c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov        }
378967c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov        return true;
379067c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov    }
379167c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov
379267c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov    /**
379367c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov     * Returns true if a value (possibly null) is specified for at least one of the supplied keys.
379467c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov     */
3795dd0e0f44fe403ff201d46d5534f7f1148e5ad729Dmitri Plotnikov    private static boolean areAnySpecified(ContentValues values, String[] keys) {
3796622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        for (String key : keys) {
3797dd0e0f44fe403ff201d46d5534f7f1148e5ad729Dmitri Plotnikov            if (values.containsKey(key)) {
3798dd0e0f44fe403ff201d46d5534f7f1148e5ad729Dmitri Plotnikov                return true;
3799622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
3800622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
3801dd0e0f44fe403ff201d46d5534f7f1148e5ad729Dmitri Plotnikov        return false;
3802622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    }
3803622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
38044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
38054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
38064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            String sortOrder) {
3807bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
3808bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov            Log.v(TAG, "query: " + uri);
3809bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        }
38100b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov
3811b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        final SQLiteDatabase db = mDbHelper.getReadableDatabase();
381235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
3813d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
38141f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String groupBy = null;
3815c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limit = getLimit(uri);
3816c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
3817619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // TODO: Consider writing a test case for RestrictionExceptions when you
3818619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // write a new query() block to make sure it protects restricted data.
3819a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
38204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
382135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
3822b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getSyncState().query(db, projection, selection,  selectionArgs,
382335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                        sortOrder);
382435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
3825d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
3826763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
3827619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                break;
3828619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            }
3829619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
3830d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
38314a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
3832763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
38334da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId));
38344da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(Contacts._ID + "=?");
38356bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
38366bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
38376bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
38385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            case CONTACTS_LOOKUP:
38395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            case CONTACTS_LOOKUP_ID: {
38405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                List<String> pathSegments = uri.getPathSegments();
38415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int segmentCount = pathSegments.size();
38425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segmentCount < 3) {
38435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    throw new IllegalArgumentException("URI " + uri + " is missing a lookup key");
38445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
38455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String lookupKey = pathSegments.get(2);
38465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segmentCount == 4) {
38472d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill                    // TODO: pull this out into a method and generalize to not require contactId
38485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    long contactId = Long.parseLong(pathSegments.get(3));
38495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder();
3850763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                    setTablesAndProjectionMapForContacts(lookupQb, uri, projection);
38514da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    String[] args;
38524da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    if (selectionArgs == null) {
38534da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        args = new String[2];
38544da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    } else {
38554da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        args = new String[selectionArgs.length + 2];
38564da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length);
38574da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    }
38584da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    args[0] = String.valueOf(contactId);
38594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    args[1] = lookupKey;
38604da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    lookupQb.appendWhere(Contacts._ID + "=? AND " + Contacts.LOOKUP_KEY + "=?");
38614da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    Cursor c = query(db, lookupQb, projection, selection, args, sortOrder,
38625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            groupBy, limit);
38635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (c.getCount() != 0) {
38645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        return c;
38655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
38665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
38675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    c.close();
38685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
38695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
3870763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
38714da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs,
38724da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        String.valueOf(lookupContactIdByLookupKey(db, lookupKey)));
38734da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(Contacts._ID + "=?");
38745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                break;
38755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
38765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
3877f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey            case CONTACTS_AS_VCARD: {
3878f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey                // When reading as vCard always use restricted view
3879f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey                final String lookupKey = uri.getPathSegments().get(2);
3880763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                qb.setTables(mDbHelper.getContactView(true /* require restricted */));
3881f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey                qb.setProjectionMap(sContactsVCardProjectionMap);
38824da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs,
38834da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        String.valueOf(lookupContactIdByLookupKey(db, lookupKey)));
38844da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(Contacts._ID + "=?");
3885f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey                break;
3886f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey            }
3887f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey
3888ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_FILTER: {
3889763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
3890ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
38914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
38924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
3893e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    sb.append(Contacts._ID + " IN ");
38945e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    appendContactFilterAsNestedQuery(sb, filterParam);
38954a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(sb.toString());
3896ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
3897ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
3898ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
3899ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
3900ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_STREQUENT_FILTER:
3901ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_STREQUENT: {
39024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                String filterSql = null;
3903ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                if (match == CONTACTS_STREQUENT_FILTER
3904d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        && uri.getPathSegments().size() > 3) {
39054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
39064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
3907e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    sb.append(Contacts._ID + " IN ");
39085e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    appendContactFilterAsNestedQuery(sb, filterParam);
39094a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    filterSql = sb.toString();
39104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
39114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
3912763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
3913ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
39145e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                String[] starredProjection = null;
39155e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                String[] frequentProjection = null;
39165e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                if (projection != null) {
39175e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                    starredProjection = appendProjectionArg(projection, TIMES_CONTACED_SORT_COLUMN);
39185e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                    frequentProjection = appendProjectionArg(projection, TIMES_CONTACED_SORT_COLUMN);
39195e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                }
39205e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar
39214a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                // Build the first query for starred
39224a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
39234a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
3924d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
39255e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                qb.setProjectionMap(sStrequentStarredProjectionMap);
39265e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                final String starredQuery = qb.buildQuery(starredProjection, Contacts.STARRED + "=1",
39274a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
3928d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
3929d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Build the second query for frequent
3930d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                qb = new SQLiteQueryBuilder();
3931763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
39324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
39334a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
3934d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
39355e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                qb.setProjectionMap(sStrequentFrequentProjectionMap);
39365e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                final String frequentQuery = qb.buildQuery(frequentProjection,
3937d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        Contacts.TIMES_CONTACTED + " > 0 AND (" + Contacts.STARRED
3938d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        + " = 0 OR " + Contacts.STARRED + " IS NULL)",
39394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
3940d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
3941d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Put them together
3942d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery},
3943d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        STREQUENT_ORDER_BY, STREQUENT_LIMIT);
39444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                Cursor c = db.rawQuery(query, null);
39454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (c != null) {
3946d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                    c.setNotificationUri(getContext().getContentResolver(),
3947d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                            ContactsContract.AUTHORITY_URI);
3948d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
3949d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                return c;
3950d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar            }
3951d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
3952ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_GROUP: {
3953763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
3954b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                if (uri.getPathSegments().size() > 2) {
395571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    qb.appendWhere(CONTACTS_IN_GROUP_SELECT);
39564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
3957b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                }
3958b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                break;
3959b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            }
3960b67163a1088f09c59f324350662eb18772fac6b6Evan Millar
3961d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_DATA: {
39624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
396382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
39644da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId));
39654da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?");
39666bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
39676bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
396800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
3969ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_PHOTO: {
39703653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
397182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
39724da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId));
39734da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?");
39743653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID);
39753653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                break;
39763653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov            }
39773653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
39784a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case PHONES: {
397982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
398089c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
39812815f58f72f109790585931f601a63ddc02536a5Evan Millar                break;
39822815f58f72f109790585931f601a63ddc02536a5Evan Millar            }
39832815f58f72f109790585931f601a63ddc02536a5Evan Millar
398448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID: {
398582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
39864da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
398748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
39884da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=?");
398948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                break;
399048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            }
399148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
3992ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case PHONES_FILTER: {
399382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, true);
399489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
3995ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
39964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
39974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
3998a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov                    sb.append(" AND (");
39995e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
40005e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    boolean orNeeded = false;
40015e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    String normalizedName = NameNormalizer.normalize(filterParam);
40025e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    if (normalizedName.length() > 0) {
40035e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append(Data.RAW_CONTACT_ID + " IN ");
40047318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov                        appendRawContactsByNormalizedNameFilter(sb, normalizedName, false);
40055e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        orNeeded = true;
40065e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    }
40075e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
40085e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    if (isPhoneNumber(filterParam)) {
40095e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        if (orNeeded) {
40105e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                            sb.append(" OR ");
40115e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        }
40125e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        String number = PhoneNumberUtils.convertKeypadLettersToDigits(filterParam);
40135e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        String reversed = PhoneNumberUtils.getStrippedReversed(number);
40145e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append(Data._ID +
40155e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                                " IN (SELECT " + PhoneLookupColumns.DATA_ID
40165e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                                  + " FROM " + Tables.PHONE_LOOKUP
40175e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                                  + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '%");
40185e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append(reversed);
40195e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append("')");
40205e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    }
40215e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    sb.append(")");
4022a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov                    qb.appendWhere(sb);
4023ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
40245e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                groupBy = PhoneColumns.NORMALIZED_NUMBER + "," + RawContacts.CONTACT_ID;
4025a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov                if (sortOrder == null) {
4026a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov                    sortOrder = Contacts.IN_VISIBLE_GROUP + " DESC, " + RawContacts.CONTACT_ID;
4027a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov                }
4028ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
4029ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
4030ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
40314a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case EMAILS: {
403282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
403389c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
40344a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                break;
40354a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            }
40364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
403748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID: {
403882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
40394da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
40404da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"
40414da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        + " AND " + Data._ID + "=?");
404248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                break;
404348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            }
404448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
40455e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            case EMAILS_LOOKUP: {
404682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
404789c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
40484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (uri.getPathSegments().size() > 2) {
40494da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
40504da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    qb.appendWhere(" AND " + Email.DATA + "=?");
40514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
4052ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
4053ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
4054ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
40555e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            case EMAILS_FILTER: {
405682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, true);
405707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                String filterParam = null;
405807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                if (uri.getPathSegments().size() > 3) {
405907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    filterParam = uri.getLastPathSegment();
406007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    if (TextUtils.isEmpty(filterParam)) {
406107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                        filterParam = null;
406207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    }
406307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                }
40645e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
406507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                if (filterParam == null) {
406607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    // If the filter is unspecified, return nothing
406707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    qb.appendWhere(" AND 0");
406807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                } else {
406907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    StringBuilder sb = new StringBuilder();
407007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    sb.append(" AND " + Data._ID + " IN (");
407107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    sb.append(
407207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                            "SELECT " + Data._ID +
407307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                            " FROM " + Tables.DATA +
407407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                            " WHERE " + DataColumns.MIMETYPE_ID + "=" + mMimeTypeIdEmail +
407507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                            " AND " + Data.DATA1 + " LIKE ");
407607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%');
407720938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov                    if (!filterParam.contains("@")) {
407820938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov                        String normalizedName = NameNormalizer.normalize(filterParam);
407920938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov                        if (normalizedName.length() > 0) {
408007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov
408107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                            /*
408207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * Using a UNION instead of an "OR" to make SQLite use the right
408307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * indexes. We need it to use the (mimetype,data1) index for the
408407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * email lookup (see above), but not for the name lookup.
408507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * SQLite is not smart enough to use the index on one side of an OR
408607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * but not on the other. Using two separate nested queries
408707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * and a UNION between them does the job.
408807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             */
408907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                            sb.append(
409007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                                    " UNION SELECT " + Data._ID +
409107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                                    " FROM " + Tables.DATA +
409207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                                    " WHERE +" + DataColumns.MIMETYPE_ID + "=" + mMimeTypeIdEmail +
409307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                                    " AND " + Data.RAW_CONTACT_ID + " IN ");
40947318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov                            appendRawContactsByNormalizedNameFilter(sb, normalizedName, false);
409520938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov                        }
40965e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    }
40975e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    sb.append(")");
4098a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov                    qb.appendWhere(sb);
40995e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                }
41005e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                groupBy = Email.DATA + "," + RawContacts.CONTACT_ID;
4101a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov                if (sortOrder == null) {
4102a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov                    sortOrder = Contacts.IN_VISIBLE_GROUP + " DESC, " + RawContacts.CONTACT_ID;
4103a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov                }
41045e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                break;
41055e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            }
41065e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
4107ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case POSTALS: {
410882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
410989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '"
411089c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                        + StructuredPostal.CONTENT_ITEM_TYPE + "'");
4111ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
4112ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
4113ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
411448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID: {
411582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
41164da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
411748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '"
411848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                        + StructuredPostal.CONTENT_ITEM_TYPE + "'");
41194da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=?");
412048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                break;
412148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            }
412248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
41235ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
4124763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForRawContacts(qb, uri);
41254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
41264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
41274f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
41285ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
41295ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
4130763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForRawContacts(qb, uri);
41314da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId));
41324da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + RawContacts._ID + "=?");
41334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
41344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
41354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
41365ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
41375ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = Long.parseLong(uri.getPathSegments().get(1));
413882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
41394da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId));
41404da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?");
4141e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
4142e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
4143e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
4144e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            case DATA: {
414582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
4146e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
4147e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
4148e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
41494f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            case DATA_ID: {
415082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
41514da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
41524da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=?");
4153a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov                break;
4154a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov            }
4155a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov
4156a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case PHONE_LOOKUP: {
41574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
4158a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                if (TextUtils.isEmpty(sortOrder)) {
4159a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // Default the sort order to something reasonable so we get consistent
4160a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // results when callers don't request an ordering
4161e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                    sortOrder = RawContactsColumns.CONCRETE_ID;
4162a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                }
4163a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
4164e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : "";
4165b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                mDbHelper.buildPhoneLookupAndContactQuery(qb, number);
4166e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                qb.setProjectionMap(sPhoneLookupProjectionMap);
4167e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov
4168e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                // Phone lookup cannot be combined with a selection
4169e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                selection = null;
4170e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                selectionArgs = null;
4171a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
4172a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
4173a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
4174ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
4175b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getGroupView());
4176ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
417789c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
4178ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
4179ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
4180ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
4181ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
4182b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getGroupView());
4183ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
41844da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
41854da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(Groups._ID + "=?");
4186ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
4187ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
4188ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
4189ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_SUMMARY: {
4190b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getGroupView() + " AS groups");
4191ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsSummaryProjectionMap);
419289c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
419389c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                groupBy = Groups._ID;
4194ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
4195ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
4196ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
4197b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
41980c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov                qb.setTables(Tables.AGGREGATION_EXCEPTIONS);
4199b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                qb.setProjectionMap(sAggregationExceptionsProjectionMap);
4200b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
4201b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
4202b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
420331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_SUGGESTIONS: {
4204d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
42052d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                String filter = null;
42062d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                if (uri.getPathSegments().size() > 3) {
42072d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                    filter = uri.getPathSegments().get(3);
42082d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                }
420931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                final int maxSuggestions;
4210d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                if (limit != null) {
4211d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                    maxSuggestions = Integer.parseInt(limit);
421231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                } else {
421331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                    maxSuggestions = DEFAULT_MAX_SUGGESTIONS;
421431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                }
421531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
4216763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
42177581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov
42187581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov                return mContactAggregator.queryAggregationSuggestions(qb, projection, contactId,
42192d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                        maxSuggestions, filter);
422031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
422131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
4222eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
4223eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                qb.setTables(Tables.SETTINGS);
4224eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                qb.setProjectionMap(sSettingsProjectionMap);
422589c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
4226e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
4227e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                // When requesting specific columns, this query requires
4228e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                // late-binding of the GroupMembership MIME-type.
4229b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                final String groupMembershipMimetypeId = Long.toString(mDbHelper
4230e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                        .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE));
423182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                if (projection != null && projection.length != 0 &&
4232b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                        mDbHelper.isInProjection(projection, Settings.UNGROUPED_COUNT)) {
4233e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                    selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId);
4234e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                }
423582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                if (projection != null && projection.length != 0 &&
4236b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                        mDbHelper.isInProjection(projection, Settings.UNGROUPED_WITH_PHONES)) {
4237e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                    selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId);
4238e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                }
4239e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
4240eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
4241eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
4242eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
424382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES: {
42440a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                setTableAndProjectionMapForStatusUpdates(qb, projection);
42455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
42465ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
42475ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
424882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES_ID: {
42490a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                setTableAndProjectionMapForStatusUpdates(qb, projection);
42504da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
42514da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(DataColumns.CONCRETE_ID + "=?");
42525ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
42535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
42545ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
4255c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS: {
4256a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov                return mGlobalSearchSupport.handleSearchSuggestionsQuery(db, uri, limit);
4257c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
4258c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
4259c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT: {
42602d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill                String lookupKey = uri.getLastPathSegment();
42612d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill                return mGlobalSearchSupport.handleSearchShortcutRefresh(db, lookupKey, projection);
4262c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
4263c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
42641b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS:
4265b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getContactView());
42661b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
42671b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
42681b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
42691b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_WITH_PHONES:
4270b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getContactView());
42711b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
42721b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1");
42731b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
42741b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
42751b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_FAVORITES:
4276b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getContactView());
42771b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
42781b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(Contacts.STARRED + "=1");
42791b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
42801b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
42811b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_GROUP_NAME:
4282b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getContactView());
42831b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
428471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                qb.appendWhere(CONTACTS_IN_GROUP_SELECT);
42851b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
42861b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
42871b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
428846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana            case RAW_CONTACT_ENTITIES: {
428946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana                setTablesAndProjectionMapForRawContactsEntities(qb, uri);
429046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana                break;
429146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana            }
429246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
429346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana            case RAW_CONTACT_ENTITY_ID: {
429446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana                long rawContactId = Long.parseLong(uri.getPathSegments().get(1));
429546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana                setTablesAndProjectionMapForRawContactsEntities(qb, uri);
42964da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId));
42974da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + RawContacts._ID + "=?");
429846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana                break;
429946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana            }
430046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
43014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            default:
4302f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.query(uri, projection, selection, selectionArgs,
4303c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                        sortOrder, limit);
43044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
43054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
4306ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        Cursor cursor =
4307ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit);
4308ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        if (readBooleanQueryParameter(uri, ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, false)) {
4309ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            cursor = bundleLetterCountExtras(cursor, db, qb, selection, selectionArgs, sortOrder);
4310ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        }
4311ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        return cursor;
43125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
43135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
43145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection,
43155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            String selection, String[] selectionArgs, String sortOrder, String groupBy,
43165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            String limit) {
4317038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        if (projection != null && projection.length == 1
4318038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana                && BaseColumns._COUNT.equals(projection[0])) {
4319038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            qb.setProjectionMap(sCountProjectionMap);
4320038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        }
43215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null,
43225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sortOrder, limit);
43234f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        if (c != null) {
43244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI);
43254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
43264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        return c;
43274f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
43284f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
4329ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov    private interface AddressBookIndexQuery {
4330ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        String TITLE = "title";
4331ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        String COUNT = "count";
4332ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
4333ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        String[] COLUMNS = new String[] {
4334ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                TITLE, COUNT
4335ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        };
4336ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
4337ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        // TODO change to LOCALIZED2 once that becomes available
4338ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        String ORDER_BY = TITLE + " COLLATE LOCALIZED";
4339ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov    }
4340ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
4341ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov    /**
4342ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov     * Computes counts by the address book index titles and adds the resulting tally
4343ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov     * to the returned cursor as a bundle of extras.
4344ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov     */
4345ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov    private Cursor bundleLetterCountExtras(Cursor cursor, final SQLiteDatabase db,
4346ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            SQLiteQueryBuilder qb, String selection, String[] selectionArgs, String sortOrder) {
4347ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        String sortKey;
4348ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
4349ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        // The sort order suffix could be something like "DESC".
4350ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        // We want to preserve it in the query even though we will change
4351ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        // the sort column itself.
4352ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        String sortOrderSuffix = "";
4353ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        if (sortOrder != null) {
4354ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            int spaceIndex = sortOrder.indexOf(' ');
4355ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            if (spaceIndex != -1) {
4356ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                sortKey = sortOrder.substring(0, spaceIndex);
4357ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                sortOrderSuffix = sortOrder.substring(spaceIndex);
4358ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            } else {
4359ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                sortKey = sortOrder;
4360ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            }
4361ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        } else {
4362ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            sortKey = Contacts.SORT_KEY_PRIMARY;
4363ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        }
4364ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
4365ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        HashMap<String, String> projectionMap = Maps.newHashMap();
4366ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        projectionMap.put(AddressBookIndexQuery.TITLE,
4367ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                "UPPER(SUBSTR(" + sortKey + ",1,1)) AS " + AddressBookIndexQuery.TITLE);
4368ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        projectionMap.put(AddressBookIndexQuery.COUNT,
4369ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                "COUNT(" + Contacts._ID + ") AS " + AddressBookIndexQuery.COUNT);
4370ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        qb.setProjectionMap(projectionMap);
4371ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
4372f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov        Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs,
4373ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                AddressBookIndexQuery.ORDER_BY, null /* having */,
4374ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                AddressBookIndexQuery.ORDER_BY + sortOrderSuffix);
4375ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
4376ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        try {
4377f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov            int groupCount = indexCursor.getCount();
4378ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            String titles[] = new String[groupCount];
4379ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            int counts[] = new int[groupCount];
4380ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            for (int i = 0; i < groupCount; i++) {
4381f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov                indexCursor.moveToNext();
4382f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov                titles[i] = indexCursor.getString(0);
4383f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov                counts[i] = indexCursor.getInt(1);
4384ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            }
4385ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
4386ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            final Bundle bundle = new Bundle();
4387ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            bundle.putStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES, titles);
4388f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov            bundle.putIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS, counts);
4389ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            return new CursorWrapper(cursor) {
4390ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
4391ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                @Override
4392ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                public Bundle getExtras() {
4393ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                    return bundle;
4394ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                }
4395ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            };
4396ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        } finally {
4397f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov            indexCursor.close();
4398ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        }
4399ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov    }
4400ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
44012d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill    /**
44022d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill     * Returns the contact Id for the contact identified by the lookupKey.  Robust against changes
44032d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill     * in the lookup key:  if the key has changed, will look up the contact by the name encoded in
44042d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill     * the lookup key.
44052d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill     */
44062d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill    public long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) {
44075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        ContactLookupKey key = new ContactLookupKey();
44085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        ArrayList<LookupKeySegment> segments = key.parse(lookupKey);
44095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long contactId = lookupContactIdBySourceIds(db, segments);
44115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (contactId == -1) {
44125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            contactId = lookupContactIdByDisplayNames(db, segments);
44135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
44145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return contactId;
44165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
44175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private interface LookupBySourceIdQuery {
44195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String TABLE = Tables.RAW_CONTACTS;
44205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String COLUMNS[] = {
44225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.CONTACT_ID,
44235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
44245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
44255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.SOURCE_ID
44265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        };
44275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int CONTACT_ID = 0;
44295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_TYPE = 1;
44305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_NAME = 2;
44315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int SOURCE_ID = 3;
44325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
44335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdBySourceIds(SQLiteDatabase db,
44355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                ArrayList<LookupKeySegment> segments) {
44365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int sourceIdCount = 0;
44375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
44385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
44395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.sourceIdLookup) {
44405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sourceIdCount++;
44415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
44425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
44435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (sourceIdCount == 0) {
44455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return -1;
44465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
44475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        // First try sync ids
44495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
44505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(RawContacts.SOURCE_ID + " IN (");
44515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
44525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
44535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.sourceIdLookup) {
44545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(sb, segment.key);
44555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sb.append(",");
44565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
44575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
44585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.setLength(sb.length() - 1);      // Last comma
44595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL");
44605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS,
44625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                 sb.toString(), null, null, null, null);
44635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        try {
44645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            while (c.moveToNext()) {
44655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountType = c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE);
44665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME);
44675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int accountHashCode =
44685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        ContactLookupKey.getAccountHashCode(accountType, accountName);
44695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID);
44705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                for (int i = 0; i < segments.size(); i++) {
44715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    LookupKeySegment segment = segments.get(i);
44725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (segment.sourceIdLookup && accountHashCode == segment.accountHashCode
44735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            && segment.key.equals(sourceId)) {
44745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID);
44755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        break;
44765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
44775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
44785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
44795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } finally {
44805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            c.close();
44815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
44825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return getMostReferencedContactId(segments);
44845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
44855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private interface LookupByDisplayNameQuery {
44875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS;
44885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String COLUMNS[] = {
44905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.CONTACT_ID,
44915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
44925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
44935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                NameLookupColumns.NORMALIZED_NAME
44945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        };
44955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int CONTACT_ID = 0;
44975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_TYPE = 1;
44985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_NAME = 2;
44995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int NORMALIZED_NAME = 3;
45005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
45015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
45025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdByDisplayNames(SQLiteDatabase db,
45035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                ArrayList<LookupKeySegment> segments) {
45045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int displayNameCount = 0;
45055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
45065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
45075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (!segment.sourceIdLookup) {
45085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                displayNameCount++;
45095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
45105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
45115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
45125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (displayNameCount == 0) {
45135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return -1;
45145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
45155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
45165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        // First try sync ids
45175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
45185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(NameLookupColumns.NORMALIZED_NAME + " IN (");
45195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
45205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
45215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (!segment.sourceIdLookup) {
45225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(sb, segment.key);
45235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sb.append(",");
45245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
45255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
45265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.setLength(sb.length() - 1);      // Last comma
45275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY
45285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                + " AND " + RawContacts.CONTACT_ID + " NOT NULL");
45295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
45305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS,
45315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                 sb.toString(), null, null, null, null);
45325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        try {
45335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            while (c.moveToNext()) {
45345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountType = c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE);
45355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME);
45365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int accountHashCode =
45375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        ContactLookupKey.getAccountHashCode(accountType, accountName);
45385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME);
45395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                for (int i = 0; i < segments.size(); i++) {
45405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    LookupKeySegment segment = segments.get(i);
45415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (!segment.sourceIdLookup && accountHashCode == segment.accountHashCode
45425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            && segment.key.equals(name)) {
45435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID);
45445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        break;
45455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
45465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
45475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
45485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } finally {
45495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            c.close();
45505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
45515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
45525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return getMostReferencedContactId(segments);
45535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
45545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
45555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    /**
45565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov     * Returns the contact ID that is mentioned the highest number of times.
45575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov     */
45585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) {
45595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Collections.sort(segments);
45605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
45615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long bestContactId = -1;
45625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int bestRefCount = 0;
45635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
45645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long contactId = -1;
45655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int count = 0;
45665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
45675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int segmentCount = segments.size();
45685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segmentCount; i++) {
45695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
45705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.contactId != -1) {
45715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segment.contactId == contactId) {
45725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    count++;
45735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                } else {
45745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (count > bestRefCount) {
45755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        bestContactId = contactId;
45765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        bestRefCount = count;
45775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
45785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    contactId = segment.contactId;
45795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    count = 1;
45805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
45815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
45825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
45835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (count > bestRefCount) {
45845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return contactId;
45855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } else {
45865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return bestContactId;
45875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
45885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
45895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
4590763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar    private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri,
4591763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar            String[] projection) {
459282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
4593763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        boolean excludeRestrictedData = false;
4594f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String requestingPackage = getQueryParameter(uri,
4595763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                ContactsContract.REQUESTING_PACKAGE_PARAM_KEY);
4596763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        if (requestingPackage != null) {
4597d91272b48f97243533c6580981e12a4847b5783fJeff Hamilton            excludeRestrictedData = !mDbHelper.hasAccessToRestrictedData(requestingPackage);
4598763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        }
4599763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        sb.append(mDbHelper.getContactView(excludeRestrictedData));
4600b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        if (mDbHelper.isInProjection(projection,
460182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_PRESENCE)) {
460282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE +
460382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                    " ON (" + Contacts._ID + " = " + AggregatedPresenceColumns.CONTACT_ID + ")");
460482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        }
4605b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        if (mDbHelper.isInProjection(projection,
460682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_STATUS,
460782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_STATUS_RES_PACKAGE,
460882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_STATUS_ICON,
460982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_STATUS_LABEL,
461082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_STATUS_TIMESTAMP)) {
46113296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey            sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " "
46123296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                    + ContactsStatusUpdatesColumns.ALIAS +
4613a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    " ON (" + ContactsColumns.LAST_STATUS_UPDATE_ID + "="
46143296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                            + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")");
461582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        }
461682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        qb.setTables(sb.toString());
461782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        qb.setProjectionMap(sContactsProjectionMap);
461882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    }
4619ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
4620763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar    private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) {
4621763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        StringBuilder sb = new StringBuilder();
4622763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        boolean excludeRestrictedData = false;
4623f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String requestingPackage = getQueryParameter(uri,
4624763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                ContactsContract.REQUESTING_PACKAGE_PARAM_KEY);
4625763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        if (requestingPackage != null) {
4626d91272b48f97243533c6580981e12a4847b5783fJeff Hamilton            excludeRestrictedData = !mDbHelper.hasAccessToRestrictedData(requestingPackage);
4627763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        }
4628763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        sb.append(mDbHelper.getRawContactView(excludeRestrictedData));
4629763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        qb.setTables(sb.toString());
4630763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        qb.setProjectionMap(sRawContactsProjectionMap);
4631763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        appendAccountFromParameter(qb, uri);
4632763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar    }
4633763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar
463446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana    private void setTablesAndProjectionMapForRawContactsEntities(SQLiteQueryBuilder qb, Uri uri) {
463546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        // Note: currently, "export only" equals to "restricted", but may not in the future.
463646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        boolean excludeRestrictedData = readBooleanQueryParameter(uri,
463746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana                Data.FOR_EXPORT_ONLY, false);
463846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
4639f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String requestingPackage = getQueryParameter(uri,
464046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana                ContactsContract.REQUESTING_PACKAGE_PARAM_KEY);
464146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        if (requestingPackage != null) {
464246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana            excludeRestrictedData = excludeRestrictedData
464346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana                    || !mDbHelper.hasAccessToRestrictedData(requestingPackage);
464446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        }
464546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        qb.setTables(mDbHelper.getContactEntitiesView(excludeRestrictedData));
464646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        qb.setProjectionMap(sRawContactsEntityProjectionMap);
464746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        appendAccountFromParameter(qb, uri);
464846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana    }
464946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
465082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri,
465182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            String[] projection, boolean distinct) {
465282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
4653d237c80845d8e13164d34278d3c20e31f8d80b4dDaisuke Miyakawa        // Note: currently, "export only" equals to "restricted", but may not in the future.
4654763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        boolean excludeRestrictedData = readBooleanQueryParameter(uri,
4655d237c80845d8e13164d34278d3c20e31f8d80b4dDaisuke Miyakawa                Data.FOR_EXPORT_ONLY, false);
4656763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar
4657f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String requestingPackage = getQueryParameter(uri,
4658763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                ContactsContract.REQUESTING_PACKAGE_PARAM_KEY);
4659763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        if (requestingPackage != null) {
4660763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar            excludeRestrictedData = excludeRestrictedData
4661d91272b48f97243533c6580981e12a4847b5783fJeff Hamilton                    || !mDbHelper.hasAccessToRestrictedData(requestingPackage);
4662763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        }
4663763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar
4664763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        sb.append(mDbHelper.getDataView(excludeRestrictedData));
466582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sb.append(" data");
466682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov
46673296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        // Include aggregated presence when requested
4668b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        if (mDbHelper.isInProjection(projection, Data.CONTACT_PRESENCE)) {
466982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE +
46703296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                    " ON (" + AggregatedPresenceColumns.CONCRETE_CONTACT_ID + "="
467182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                    + RawContacts.CONTACT_ID + ")");
467282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        }
467382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov
46743296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        // Include aggregated status updates when requested
4675b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        if (mDbHelper.isInProjection(projection,
467682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Data.CONTACT_STATUS,
467782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Data.CONTACT_STATUS_RES_PACKAGE,
467882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Data.CONTACT_STATUS_ICON,
467982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Data.CONTACT_STATUS_LABEL,
468082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Data.CONTACT_STATUS_TIMESTAMP)) {
46813296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey            sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " "
46823296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                    + ContactsStatusUpdatesColumns.ALIAS +
468382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                    " ON (" + ContactsColumns.LAST_STATUS_UPDATE_ID + "="
46843296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                            + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")");
4685ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        }
46863296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey
46873296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        // Include individual presence when requested
46883296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        if (mDbHelper.isInProjection(projection, Data.PRESENCE)) {
46893296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey            sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE +
46903296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                    " ON (" + StatusUpdates.DATA_ID + "="
46913296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                    + DataColumns.CONCRETE_ID + ")");
46923296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        }
46933296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey
46943296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        // Include individual status updates when requested
46953296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        if (mDbHelper.isInProjection(projection,
46963296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                Data.STATUS,
46973296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                Data.STATUS_RES_PACKAGE,
46983296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                Data.STATUS_ICON,
46993296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                Data.STATUS_LABEL,
47003296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                Data.STATUS_TIMESTAMP)) {
47013296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey            sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES +
47023296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                    " ON (" + StatusUpdatesColumns.CONCRETE_DATA_ID + "="
47033296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey                            + DataColumns.CONCRETE_ID + ")");
47043296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey        }
47053296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey
470682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        qb.setTables(sb.toString());
470782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        qb.setProjectionMap(distinct ? sDistinctDataProjectionMap : sDataProjectionMap);
470882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        appendAccountFromParameter(qb, uri);
4709ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    }
4710ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
47110a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov    private void setTableAndProjectionMapForStatusUpdates(SQLiteQueryBuilder qb,
47120a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            String[] projection) {
47130a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        StringBuilder sb = new StringBuilder();
4714b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        sb.append(mDbHelper.getDataView());
47150a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        sb.append(" data");
47160a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
4717b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        if (mDbHelper.isInProjection(projection, StatusUpdates.PRESENCE)) {
47180a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE +
47190a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                    " ON(" + Tables.PRESENCE + "." + StatusUpdates.DATA_ID
47200a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                    + "=" + DataColumns.CONCRETE_ID + ")");
47210a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        }
47220a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
4723b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        if (mDbHelper.isInProjection(projection,
47240a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                StatusUpdates.STATUS,
47250a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                StatusUpdates.STATUS_RES_PACKAGE,
47260a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                StatusUpdates.STATUS_ICON,
47270a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                StatusUpdates.STATUS_LABEL,
47280a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                StatusUpdates.STATUS_TIMESTAMP)) {
47290a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES +
47300a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                    " ON(" + Tables.STATUS_UPDATES + "." + StatusUpdatesColumns.DATA_ID
47310a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                    + "=" + DataColumns.CONCRETE_ID + ")");
47320a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        }
47330a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        qb.setTables(sb.toString());
47340a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        qb.setProjectionMap(sStatusUpdatesProjectionMap);
47350a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov    }
47360a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
47374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) {
4738f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME);
4739f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE);
4740e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
4741e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType);
4742e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (partialUri) {
4743e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            // Throw when either account is incomplete
4744e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            throw new IllegalArgumentException("Must specify both or neither of"
4745e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                    + " ACCOUNT_NAME and ACCOUNT_TYPE");
4746e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        }
4747e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
4748e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // Accounts are valid by only checking one parameter, since we've
4749e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // already ruled out partial accounts.
4750e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean validAccount = !TextUtils.isEmpty(accountName);
4751e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (validAccount) {
47524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
47534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountName) + " AND "
47544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + RawContacts.ACCOUNT_TYPE + "="
47554a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountType));
47564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        } else {
47574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere("1");
47584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        }
47594a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    }
47604a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
4761e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong    private String appendAccountToSelection(Uri uri, String selection) {
4762f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME);
4763f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE);
4764e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
4765e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType);
4766e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (partialUri) {
4767e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            // Throw when either account is incomplete
4768e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            throw new IllegalArgumentException("Must specify both or neither of"
4769e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                    + " ACCOUNT_NAME and ACCOUNT_TYPE");
4770e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        }
4771e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
4772e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // Accounts are valid by only checking one parameter, since we've
4773e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // already ruled out partial accounts.
4774e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean validAccount = !TextUtils.isEmpty(accountName);
4775e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (validAccount) {
4776e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "="
4777e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + DatabaseUtils.sqlEscapeString(accountName) + " AND "
4778e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + RawContacts.ACCOUNT_TYPE + "="
4779e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + DatabaseUtils.sqlEscapeString(accountType));
4780e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            if (!TextUtils.isEmpty(selection)) {
4781e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(" AND (");
4782e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(selection);
4783e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(')');
4784e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            }
4785e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            return selectionSb.toString();
4786e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        } else {
4787e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            return selection;
4788e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        }
4789e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong    }
4790e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong
47917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
4792c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * Gets the value of the "limit" URI query parameter.
4793c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *
4794c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * @return A string containing a non-negative integer, or <code>null</code> if
4795c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *         the parameter is not set, or is set to an invalid value.
4796c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     */
4797f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    private String getLimit(Uri uri) {
4798f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String limitParam = getQueryParameter(uri, "limit");
4799c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limitParam == null) {
4800c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
4801c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
4802c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        // make sure that the limit is a non-negative integer
4803c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        try {
4804c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            int l = Integer.parseInt(limitParam);
4805c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            if (l < 0) {
4806c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                Log.w(TAG, "Invalid limit parameter: " + limitParam);
4807c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return null;
4808c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
4809c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return String.valueOf(l);
4810c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        } catch (NumberFormatException ex) {
4811c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            Log.w(TAG, "Invalid limit parameter: " + limitParam);
4812c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
4813c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
4814c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
4815c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
48165e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    /**
48175e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov     * Returns true if all the characters are meaningful as digits
48185e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov     * in a phone number -- letters, digits, and a few punctuation marks.
48195e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov     */
48205e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    private boolean isPhoneNumber(CharSequence cons) {
48215e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        int len = cons.length();
48225e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
48235e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        for (int i = 0; i < len; i++) {
48245e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            char c = cons.charAt(i);
48255e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
48265e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            if ((c >= '0') && (c <= '9')) {
48275e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                continue;
48285e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            }
48295e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            if ((c == ' ') || (c == '-') || (c == '(') || (c == ')') || (c == '.') || (c == '+')
48305e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    || (c == '#') || (c == '*')) {
48315e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                continue;
48325e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            }
48335e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            if ((c >= 'A') && (c <= 'Z')) {
48345e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                continue;
48355e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            }
48365e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            if ((c >= 'a') && (c <= 'z')) {
48375e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                continue;
48385e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            }
48395e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
48405e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            return false;
48415e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        }
48425e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
48435e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        return true;
48445e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    }
48455e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
484600ec508630251d6c6e3746469c9428f5a8cd5996Jeff Sharkey    String getContactsRestrictions() {
4847d91272b48f97243533c6580981e12a4847b5783fJeff Hamilton        if (mDbHelper.hasAccessToRestrictedData()) {
484870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
484970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        } else {
4850fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov            return RawContactsColumns.CONCRETE_IS_RESTRICTED + "=0";
485170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
485270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    }
485370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
485470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    public String getContactsRestrictionExceptionAsNestedQuery(String contactIdColumn) {
4855d91272b48f97243533c6580981e12a4847b5783fJeff Hamilton        if (mDbHelper.hasAccessToRestrictedData()) {
485670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
485767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        } else {
48585ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return "(SELECT " + RawContacts.IS_RESTRICTED + " FROM " + Tables.RAW_CONTACTS
48595ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + " WHERE " + RawContactsColumns.CONCRETE_ID + "=" + contactIdColumn + ")=0";
4860619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
4861619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
4862619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
4863b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    @Override
4864b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
4865b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        int match = sUriMatcher.match(uri);
4866b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        switch (match) {
4867d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            case CONTACTS_PHOTO: {
4868b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                if (!"r".equals(mode)) {
4869b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                    throw new FileNotFoundException("Mode " + mode + " not supported.");
4870b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                }
4871b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
4872b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                String sql =
4873b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                        "SELECT " + Photo.PHOTO + " FROM " + mDbHelper.getDataView() +
4874b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                        " WHERE " + Data._ID + "=" + Contacts.PHOTO_ID
48754da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                                + " AND " + RawContacts.CONTACT_ID + "=?";
4876b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                SQLiteDatabase db = mDbHelper.getReadableDatabase();
48774da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                return SQLiteContentHelper.getBlobColumnAsAssetFile(db, sql,
48784da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        new String[]{uri.getPathSegments().get(1)});
4879d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            }
4880d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
4881f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey            case CONTACTS_AS_VCARD: {
4882d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                final String lookupKey = uri.getPathSegments().get(2);
4883d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                final long contactId = lookupContactIdByLookupKey(mDb, lookupKey);
488414b8a1243ab5c043b35e47527ca1c962064f3771Daisuke Miyakawa                final String selection = Contacts._ID + "=" + contactId;
4885d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
4886d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                // When opening a contact as file, we pass back contents as a
4887d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                // vCard-encoded stream. We build into a local buffer first,
4888d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                // then pipe into MemoryFile once the exact size is known.
4889d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                final ByteArrayOutputStream localStream = new ByteArrayOutputStream();
4890d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                outputRawContactsAsVCard(localStream, selection, null);
4891d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                return buildAssetFileDescriptor(localStream);
4892d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            }
4893b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
4894b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov            default:
4895b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                throw new FileNotFoundException("No file at: " + uri);
4896b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        }
4897b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    }
4898b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
4899d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile";
4900d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
4901d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    /**
4902d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * Build a {@link AssetFileDescriptor} through a {@link MemoryFile} with the
4903d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * contents of the given {@link ByteArrayOutputStream}.
4904d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     */
4905d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) {
4906d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        AssetFileDescriptor fd = null;
4907d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        try {
4908d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            stream.flush();
4909d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
4910d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            final byte[] byteData = stream.toByteArray();
4911d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            final int size = byteData.length;
4912d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
4913d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            final MemoryFile memoryFile = new MemoryFile(CONTACT_MEMORY_FILE_NAME, size);
4914d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            memoryFile.writeBytes(byteData, 0, 0, size);
4915d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            memoryFile.deactivate();
4916b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
4917d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            fd = AssetFileDescriptor.fromMemoryFile(memoryFile);
4918d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        } catch (IOException e) {
4919d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            Log.w(TAG, "Problem writing stream into an AssetFileDescriptor: " + e.toString());
4920d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        }
4921d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        return fd;
4922d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    }
4923d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
4924d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    /**
4925d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * Output {@link RawContacts} matching the requested selection in the vCard
4926d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * format to the given {@link OutputStream}. This method returns silently if
4927d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * any errors encountered.
4928d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     */
4929d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    private void outputRawContactsAsVCard(OutputStream stream, String selection,
4930d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            String[] selectionArgs) {
4931d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        final Context context = this.getContext();
49327a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa        final VCardComposer composer =
49337a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa                new VCardComposer(context, VCardConfig.VCARD_TYPE_DEFAULT, false);
4934d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        composer.addHandler(composer.new HandlerForOutputStream(stream));
4935d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
4936f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey        // No extra checks since composer always uses restricted views
49377a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa        if (!composer.init(selection, selectionArgs)) {
49387a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa            Log.w(TAG, "Failed to init VCardComposer");
4939d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            return;
49407a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa        }
4941d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
4942d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        while (!composer.isAfterLast()) {
4943d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            if (!composer.createOneEntry()) {
4944d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                Log.w(TAG, "Failed to output a contact.");
4945d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            }
4946d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        }
4947d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        composer.terminate();
4948d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    }
4949b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
49504f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
49514f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public String getType(Uri uri) {
4952a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
49534f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
4954b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS:
4955be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov                return Contacts.CONTENT_TYPE;
49562d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill            case CONTACTS_LOOKUP:
4957b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS_ID:
4958b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS_LOOKUP_ID:
4959b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Contacts.CONTENT_ITEM_TYPE;
4960f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey            case CONTACTS_AS_VCARD:
4961f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey                return Contacts.CONTENT_VCARD_TYPE;
4962b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case RAW_CONTACTS:
4963be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov                return RawContacts.CONTENT_TYPE;
4964b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case RAW_CONTACTS_ID:
4965b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return RawContacts.CONTENT_ITEM_TYPE;
4966508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            case DATA_ID:
4967b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getDataMimeType(ContentUris.parseId(uri));
496848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES:
496948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Phone.CONTENT_TYPE;
497048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID:
497148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Phone.CONTENT_ITEM_TYPE;
497248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS:
497348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Email.CONTENT_TYPE;
497448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID:
497548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Email.CONTENT_ITEM_TYPE;
497648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS:
497748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return StructuredPostal.CONTENT_TYPE;
497848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID:
497948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return StructuredPostal.CONTENT_ITEM_TYPE;
4980b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_EXCEPTIONS:
4981b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return AggregationExceptions.CONTENT_TYPE;
4982b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_EXCEPTION_ID:
4983b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return AggregationExceptions.CONTENT_ITEM_TYPE;
4984b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case SETTINGS:
4985b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Settings.CONTENT_TYPE;
4986b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_SUGGESTIONS:
4987b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Contacts.CONTENT_TYPE;
4988c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS:
4989c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SUGGEST_MIME_TYPE;
4990c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT:
4991c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SHORTCUT_MIME_TYPE;
499261efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov            default:
499361efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov                return mLegacyApiSupport.getType(uri);
49944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
49954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
49967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
49975dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    private void setDisplayName(long rawContactId, int displayNameSource,
49985dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            String displayNamePrimary, String displayNameAlternative, String phoneticName,
49995dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            int phoneticNameStyle, String sortKeyPrimary, String sortKeyAlternative) {
50005dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        mRawContactDisplayNameUpdate.bindLong(1, displayNameSource);
50015dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        bindString(mRawContactDisplayNameUpdate, 2, displayNamePrimary);
50025dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        bindString(mRawContactDisplayNameUpdate, 3, displayNameAlternative);
50035dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        bindString(mRawContactDisplayNameUpdate, 4, phoneticName);
50045dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        mRawContactDisplayNameUpdate.bindLong(5, phoneticNameStyle);
50055dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        bindString(mRawContactDisplayNameUpdate, 6, sortKeyPrimary);
50065dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        bindString(mRawContactDisplayNameUpdate, 7, sortKeyAlternative);
50075dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        mRawContactDisplayNameUpdate.bindLong(8, rawContactId);
500825abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        mRawContactDisplayNameUpdate.execute();
50093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
50103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
501173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /**
501273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Sets the {@link RawContacts#DIRTY} for the specified raw contact.
501373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     */
501473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private void setRawContactDirty(long rawContactId) {
5015a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov        mDirtyRawContacts.add(rawContactId);
501673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    }
501773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
5018c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
5019c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to primary, and resets all data records of
5020c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * the same mimetype and under the same contact to not be primary.
5021c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
5022c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
5023c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
5024653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    private void setIsPrimary(long rawContactId, long dataId, long mimeTypeId) {
5025c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.bindLong(1, dataId);
5026653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetPrimaryStatement.bindLong(2, mimeTypeId);
5027653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetPrimaryStatement.bindLong(3, rawContactId);
5028c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.execute();
5029c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
5030c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
5031c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
5032c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to "super primary", and resets all data
5033c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * records of the same mimetype and under the same aggregate to not be "super primary".
5034c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
5035c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
5036c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
5037653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    private void setIsSuperPrimary(long rawContactId, long dataId, long mimeTypeId) {
5038c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.bindLong(1, dataId);
5039653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetSuperPrimaryStatement.bindLong(2, mimeTypeId);
5040653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetSuperPrimaryStatement.bindLong(3, rawContactId);
5041c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.execute();
5042c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
5043ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
5044f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    public void insertNameLookupForEmail(long rawContactId, long dataId, String email) {
5045f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (TextUtils.isEmpty(email)) {
5046f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            return;
5047f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
5048f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5049f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(email);
5050f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (tokens.length == 0) {
5051f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            return;
5052f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
5053f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5054f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        String address = tokens[0].getAddress();
5055f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        int at = address.indexOf('@');
5056f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (at != -1) {
5057f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            address = address.substring(0, at);
5058f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
5059f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5060f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        insertNameLookup(rawContactId, dataId,
5061f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                NameLookupType.EMAIL_BASED_NICKNAME, NameNormalizer.normalize(address));
5062f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
5063f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5064f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    /**
5065f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     * Normalizes the nickname and inserts it in the name lookup table.
5066f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     */
5067f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    public void insertNameLookupForNickname(long rawContactId, long dataId, String nickname) {
5068f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (TextUtils.isEmpty(nickname)) {
5069f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            return;
5070f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
5071f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5072f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        insertNameLookup(rawContactId, dataId,
5073f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                NameLookupType.NICKNAME, NameNormalizer.normalize(nickname));
5074f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
5075f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5076a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka    public void insertNameLookupForOrganization(long rawContactId, long dataId, String company,
5077a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            String title) {
5078a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        if (!TextUtils.isEmpty(company)) {
5079a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            insertNameLookup(rawContactId, dataId,
5080a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    NameLookupType.ORGANIZATION, NameNormalizer.normalize(company));
5081a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        }
5082a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        if (!TextUtils.isEmpty(title)) {
5083a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            insertNameLookup(rawContactId, dataId,
5084a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    NameLookupType.ORGANIZATION, NameNormalizer.normalize(title));
5085a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        }
5086a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka    }
5087f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5088f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    public void insertNameLookupForStructuredName(long rawContactId, long dataId, String name) {
5089f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        mNameLookupBuilder.insertNameLookup(rawContactId, dataId, name);
50904cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        if (!TextUtils.isEmpty(name)) {
50914cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao            Iterator<String> it = ContactLocaleUtils.getNameLookupKeys(name, FullNameStyle.CHINESE);
50924cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao            if (it != null) {
50934cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                while(it.hasNext()) {
50944cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                    String key = it.next();
50954cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                    mNameLookupBuilder.insertNameLookup(rawContactId, dataId,
50964cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                            NameLookupType.NAME_SHORTHAND,
50974cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                            mNameLookupBuilder.normalizeName(key));
50984cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                }
50994cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao            }
51004cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        }
5101f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
5102f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5103315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov    private interface NicknameLookupPreloadQuery {
5104315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        String TABLE = Tables.NICKNAME_LOOKUP;
5105315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
5106315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        String[] COLUMNS = new String[] {
5107315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov            NicknameLookupColumns.NAME
5108315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        };
5109315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
5110315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        int NAME = 0;
5111315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov    }
5112315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
5113315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov    /**
5114315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov     * Read all known common nicknames from the database and populate a Bloom
5115315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov     * filter using the corresponding hash codes. The idea is to eliminate most
5116315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov     * of unnecessary database lookups for nicknames. Given a name, we will take
51173684089aba82df3f7a0c111e7c96ed8b0380e57aDmitri Plotnikov     * its hash code and see if it is set in the Bloom filter. If not, we will know
5118315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov     * that the name is not in the database. If it is, we still need to run a
5119315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov     * query.
5120315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov     * <p>
5121315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov     * Given the size of the filter and the expected size of the nickname table,
5122315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov     * we should expect the combination of the Bloom filter and cache will
5123315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov     * prevent around 98-99% of unnecessary queries from running.
5124315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov     */
5125315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov    private void preloadNicknameBloomFilter() {
5126315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        mNicknameBloomFilter = new BitSet(NICKNAME_BLOOM_FILTER_SIZE + 1);
5127315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        SQLiteDatabase db = mDbHelper.getReadableDatabase();
5128315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        Cursor cursor = db.query(NicknameLookupPreloadQuery.TABLE,
5129315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov                NicknameLookupPreloadQuery.COLUMNS,
5130315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov                null, null, null, null, null);
5131315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        try {
5132315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov            int count = cursor.getCount();
5133315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov            for (int i = 0; i < count; i++) {
5134315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov                cursor.moveToNext();
5135315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov                String normalizedName = cursor.getString(NicknameLookupPreloadQuery.NAME);
5136315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov                int hashCode = normalizedName.hashCode();
5137315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov                mNicknameBloomFilter.set(hashCode & NICKNAME_BLOOM_FILTER_SIZE);
5138315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov            }
5139315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        } finally {
5140315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov            cursor.close();
5141315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        }
5142315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov    }
5143315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
5144315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
5145f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    /**
5146f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     * Returns nickname cluster IDs or null. Maintains cache.
5147f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     */
5148f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    protected String[] getCommonNicknameClusters(String normalizedName) {
5149315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        int hashCode = normalizedName.hashCode();
5150315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        if (!mNicknameBloomFilter.get(hashCode & NICKNAME_BLOOM_FILTER_SIZE)) {
5151315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov            return null;
5152315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        }
5153315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
5154f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        SoftReference<String[]> ref;
5155f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        String[] clusters = null;
5156f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        synchronized (mNicknameClusterCache) {
5157f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            if (mNicknameClusterCache.containsKey(normalizedName)) {
5158f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                ref = mNicknameClusterCache.get(normalizedName);
5159f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                if (ref == null) {
5160f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                    return null;
5161f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                }
5162f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                clusters = ref.get();
5163f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            }
5164f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
5165f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5166f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (clusters == null) {
5167f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            clusters = loadNicknameClusters(normalizedName);
5168f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            ref = clusters == null ? null : new SoftReference<String[]>(clusters);
5169f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            synchronized (mNicknameClusterCache) {
5170f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                mNicknameClusterCache.put(normalizedName, ref);
5171f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            }
5172f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
5173f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        return clusters;
5174f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
5175f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5176315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov    private interface NicknameLookupQuery {
5177315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        String TABLE = Tables.NICKNAME_LOOKUP;
5178315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
5179315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        String[] COLUMNS = new String[] {
5180315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov            NicknameLookupColumns.CLUSTER
5181315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        };
5182315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
5183315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov        int CLUSTER = 0;
5184315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov    }
5185315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
5186f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    protected String[] loadNicknameClusters(String normalizedName) {
5187b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        SQLiteDatabase db = mDbHelper.getReadableDatabase();
5188f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        String[] clusters = null;
5189f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        Cursor cursor = db.query(NicknameLookupQuery.TABLE, NicknameLookupQuery.COLUMNS,
5190f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                NicknameLookupColumns.NAME + "=?", new String[] { normalizedName },
5191f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                null, null, null);
5192f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        try {
5193f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            int count = cursor.getCount();
5194f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            if (count > 0) {
5195f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                clusters = new String[count];
5196f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                for (int i = 0; i < count; i++) {
5197f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                    cursor.moveToNext();
5198f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                    clusters[i] = cursor.getString(NicknameLookupQuery.CLUSTER);
5199f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                }
5200f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            }
5201f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        } finally {
5202f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            cursor.close();
5203f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
5204f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        return clusters;
5205f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
5206f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5207f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private class StructuredNameLookupBuilder extends NameLookupBuilder {
5208f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5209f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        public StructuredNameLookupBuilder(NameSplitter splitter) {
5210f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            super(splitter);
5211f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
5212f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5213f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        @Override
5214f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        protected void insertNameLookup(long rawContactId, long dataId, int lookupType,
5215f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                String name) {
5216f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            ContactsProvider2.this.insertNameLookup(rawContactId, dataId, lookupType, name);
5217f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
5218f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5219f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        @Override
5220f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        protected String[] getCommonNicknameClusters(String normalizedName) {
5221f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            return ContactsProvider2.this.getCommonNicknameClusters(normalizedName);
5222f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
5223f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
5224f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5225f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    /**
5226f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     * Inserts a record in the {@link Tables#NAME_LOOKUP} table.
5227f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     */
5228f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    public void insertNameLookup(long rawContactId, long dataId, int lookupType, String name) {
52295dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        mNameLookupInsert.bindLong(1, rawContactId);
52305dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        mNameLookupInsert.bindLong(2, dataId);
52315dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        mNameLookupInsert.bindLong(3, lookupType);
52325dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        bindString(mNameLookupInsert, 4, name);
5233f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        mNameLookupInsert.executeInsert();
5234f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
5235f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
5236f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    /**
5237f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     * Deletes all {@link Tables#NAME_LOOKUP} table rows associated with the specified data element.
5238f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     */
5239f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    public void deleteNameLookup(long dataId) {
52405dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        mNameLookupDelete.bindLong(1, dataId);
5241f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        mNameLookupDelete.execute();
5242f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
5243f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
52442d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov    public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) {
5245d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov        sb.append("(" +
5246d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                "SELECT DISTINCT " + RawContacts.CONTACT_ID +
5247d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " FROM " + Tables.RAW_CONTACTS +
5248d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " JOIN " + Tables.NAME_LOOKUP +
5249d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " ON(" + RawContactsColumns.CONCRETE_ID + "="
5250d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                        + NameLookupColumns.RAW_CONTACT_ID + ")" +
5251d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " WHERE normalized_name GLOB '");
5252e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        sb.append(NameNormalizer.normalize(filterParam));
5253d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov        sb.append("*' AND " + NameLookupColumns.NAME_TYPE + " IN("
5254d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                + NameLookupType.NAME_COLLATION_KEY + ","
5255d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                + NameLookupType.EMAIL_BASED_NICKNAME + ","
5256d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                + NameLookupType.NICKNAME + ","
52574cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                + NameLookupType.NAME_SHORTHAND + ","
5258d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                + NameLookupType.ORGANIZATION + "))");
5259e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    }
5260e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
52615ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public String getRawContactsByFilterAsNestedQuery(String filterParam) {
5262c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        StringBuilder sb = new StringBuilder();
52637318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov        appendRawContactsByFilterAsNestedQuery(sb, filterParam);
5264c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        return sb.toString();
5265c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
5266c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
52677318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov    public void appendRawContactsByFilterAsNestedQuery(StringBuilder sb, String filterParam) {
52687318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov        appendRawContactsByNormalizedNameFilter(sb, NameNormalizer.normalize(filterParam), true);
52695e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    }
52705e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
52715e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    private void appendRawContactsByNormalizedNameFilter(StringBuilder sb, String normalizedName,
52727318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov            boolean allowEmailMatch) {
5273d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov        sb.append("(" +
5274dc947a9d03279eab0fb7c3b9d8ffbb492c1e2062Dmitri Plotnikov                "SELECT " + NameLookupColumns.RAW_CONTACT_ID +
5275d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " FROM " + Tables.NAME_LOOKUP +
5276d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " WHERE " + NameLookupColumns.NORMALIZED_NAME +
5277d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " GLOB '");
52785e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sb.append(normalizedName);
5279a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        sb.append("*' AND " + NameLookupColumns.NAME_TYPE + " IN ("
5280a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                + NameLookupType.NAME_COLLATION_KEY + ","
5281a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                + NameLookupType.NICKNAME + ","
52824cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                + NameLookupType.NAME_SHORTHAND + ","
528320938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov                + NameLookupType.ORGANIZATION);
528420938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov        if (allowEmailMatch) {
528520938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov            sb.append("," + NameLookupType.EMAIL_BASED_NICKNAME);
528620938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov        }
52877318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov        sb.append("))");
5288ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    }
5289ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
52904a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /**
52914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     * Inserts an argument at the beginning of the selection arg list.
52924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     */
52934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private String[] insertSelectionArg(String[] selectionArgs, String arg) {
5294b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        if (selectionArgs == null) {
5295b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return new String[] {arg};
5296b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        } else {
5297b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            int newLength = selectionArgs.length + 1;
5298b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            String[] newSelectionArgs = new String[newLength];
52994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            newSelectionArgs[0] = arg;
53004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length);
5301b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return newSelectionArgs;
5302b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        }
5303b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    }
5304caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
53055e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar    private String[] appendProjectionArg(String[] projection, String arg) {
53065e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        if (projection == null) {
53075e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar            return null;
53085e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        }
53095e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        final int length = projection.length;
53105e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        String[] newProjection = new String[length + 1];
53115e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        System.arraycopy(projection, 0, newProjection, 0, length);
53125e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        newProjection[length] = arg;
53135e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        return newProjection;
53145e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar    }
53155e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar
5316caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    protected Account getDefaultAccount() {
5317caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        AccountManager accountManager = AccountManager.get(getContext());
5318caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        try {
5319df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana            Account[] accounts = accountManager.getAccountsByTypeAndFeatures(DEFAULT_ACCOUNT_TYPE,
5320df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                    new String[] {FEATURE_LEGACY_HOSTED_OR_GOOGLE}, null, null).getResult();
5321caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            if (accounts != null && accounts.length > 0) {
5322caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov                return accounts[0];
5323caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            }
5324caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        } catch (Throwable e) {
53256f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov            Log.e(TAG, "Cannot determine the default account for contacts compatibility", e);
5326caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        }
53276f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov        return null;
5328caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    }
5329f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5330627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov    protected boolean isWritableAccount(Account account) {
5331627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        IContentService contentService = ContentResolver.getContentService();
5332627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        try {
5333627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            for (SyncAdapterType sync : contentService.getSyncAdapterTypes()) {
5334627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                if (ContactsContract.AUTHORITY.equals(sync.authority) &&
5335627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                        account.type.equals(sync.accountType)) {
5336627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    return sync.supportsUploading();
5337627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                }
5338627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            }
5339627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        } catch (RemoteException e) {
5340627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            Log.e(TAG, "Could not acquire sync adapter types");
5341627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        }
5342627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        return false;
5343627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov    }
5344b4e61e064b59e8076df81b061add9fb358fd2ed9Dmitri Plotnikov
5345f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    /* package */ static boolean readBooleanQueryParameter(Uri uri, String parameter,
5346f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            boolean defaultValue) {
5347f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5348f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        // Manually parse the query, which is much faster than calling uri.getQueryParameter
5349f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String query = uri.getEncodedQuery();
5350f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (query == null) {
5351f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            return defaultValue;
5352f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
5353f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5354f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int index = query.indexOf(parameter);
5355f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (index == -1) {
5356f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            return defaultValue;
5357f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
5358f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5359f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        index += parameter.length();
5360f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5361f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        return !matchQueryParameter(query, index, "=0", false)
5362f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                && !matchQueryParameter(query, index, "=false", true);
5363f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    }
5364f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5365f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    private static boolean matchQueryParameter(String query, int index, String value,
5366f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            boolean ignoreCase) {
5367f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int length = value.length();
5368f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        return query.regionMatches(ignoreCase, index, value, 0, length)
5369f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                && (query.length() == index + length || query.charAt(index + length) == '&');
5370f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    }
5371f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5372f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    /**
5373f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov     * A fast re-implementation of {@link Uri#getQueryParameter}
5374f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov     */
5375f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    /* package */ static String getQueryParameter(Uri uri, String parameter) {
5376f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String query = uri.getEncodedQuery();
5377f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (query == null) {
5378f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            return null;
5379f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
5380f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5381f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int queryLength = query.length();
5382f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int parameterLength = parameter.length();
5383f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5384f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String value;
5385f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int index = 0;
5386f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        while (true) {
5387f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            index = query.indexOf(parameter, index);
5388f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            if (index == -1) {
5389f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                return null;
5390f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            }
5391f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5392f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            index += parameterLength;
5393f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5394f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            if (queryLength == index) {
5395f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                return null;
5396f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            }
5397f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5398f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            if (query.charAt(index) == '=') {
5399f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                index++;
5400f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                break;
5401f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            }
5402f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
5403f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5404f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int ampIndex = query.indexOf('&', index);
5405f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (ampIndex == -1) {
5406f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            value = query.substring(index);
5407f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        } else {
5408f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            value = query.substring(index, ampIndex);
5409f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
5410f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
5411f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        return Uri.decode(value);
5412f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    }
54135dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
54145dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    private void bindString(SQLiteStatement stmt, int index, String value) {
54155dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        if (value == null) {
54165dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            stmt.bindNull(index);
54175dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        } else {
54185dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            stmt.bindString(index, value);
54195dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        }
54205dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    }
54215dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
54225dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    private void bindLong(SQLiteStatement stmt, int index, Number value) {
54235dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        if (value == null) {
54245dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            stmt.bindNull(index);
54255dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        } else {
54265dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            stmt.bindLong(index, value.longValue());
54275dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        }
54285dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    }
54294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton}
5430