ContactsProvider2.java revision 82bd858c9911dfbd8dca52dc276333768b0a429e
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;
213de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.AggregatedPresenceColumns;
223de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.AggregationExceptionColumns;
233de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.Clauses;
243de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.ContactsColumns;
253de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.DataColumns;
263de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.DisplayNameSources;
273de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.GroupsColumns;
283de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.MimetypesColumns;
293de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.NameLookupColumns;
303de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.NameLookupType;
31f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.NicknameLookupColumns;
323de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.PhoneColumns;
333de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.PhoneLookupColumns;
343de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.PresenceColumns;
353de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.RawContactsColumns;
363de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.SettingsColumns;
37a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.StatusUpdatesColumns;
383de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.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;
4570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wongimport android.accounts.OnAccountsUpdatedListener;
46c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager;
47568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderOperation;
48568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderResult;
4935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris;
5067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues;
5167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context;
5235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.Entity;
5367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.EntityIterator;
54568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.OperationApplicationException;
553d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences;
5667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher;
573de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.content.SharedPreferences.Editor;
58b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.content.res.AssetFileDescriptor;
594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor;
60ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils;
61a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikovimport android.database.sqlite.SQLiteConstraintException;
62b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.database.sqlite.SQLiteContentHelper;
63b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.database.sqlite.SQLiteCursor;
644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase;
654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder;
66c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millarimport android.database.sqlite.SQLiteStatement;
674f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri;
68d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport android.os.MemoryFile;
69b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException;
700e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport android.os.SystemProperties;
71d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport android.pim.vcard.VCardComposer;
723d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager;
73508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns;
743de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract;
753de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.LiveFolders;
763de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.OpenableColumns;
773de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.SyncStateContract;
78b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions;
793de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Contacts;
803de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Data;
813de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Groups;
823de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.PhoneLookup;
833de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
843de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Settings;
8582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikovimport android.provider.ContactsContract.StatusUpdates;
863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.BaseTypes;
87ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Email;
88ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im;
903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname;
913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization;
92de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds.Phone;
93b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Photo;
944097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
9567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
96a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils;
97a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils;
98f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikovimport android.text.util.Rfc822Token;
99f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikovimport android.text.util.Rfc822Tokenizer;
100c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log;
1014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
102d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.ByteArrayOutputStream;
103b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport java.io.FileNotFoundException;
104d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.IOException;
105d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.OutputStream;
106f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikovimport java.lang.ref.SoftReference;
1077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList;
1085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.Collections;
109b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap;
1100e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.HashSet;
1115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.List;
112622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkeyimport java.util.Locale;
113b5a4add17815167d20a90645779df34cdf45280dFred Quintanaimport java.util.Map;
1140e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.Set;
115ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch;
1164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/**
1184f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications
1194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}.
1204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */
12170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wongpublic class ContactsProvider2 extends SQLiteContentProvider implements OnAccountsUpdatedListener {
122caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
123bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov    private static final String TAG = "ContactsProvider";
124bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov
125bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov    private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
1264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
127619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: carefully prevent all incoming nested queries; they can be gaping security holes
128619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: check for restricted flag during insert(), update(), and delete() calls
129619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
1303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Default for the maximum number of returned aggregation suggestions. */
1313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DEFAULT_MAX_SUGGESTIONS = 5;
1323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1333d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /**
1343d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * Shared preference key for the legacy contact import version. The need for a version
1353d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * as opposed to a boolean flag is that if we discover bugs in the contact import process,
1363d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * we can trigger re-import by incrementing the import version.
1373d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     */
1383d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private static final String PREF_CONTACTS_IMPORTED = "contacts_imported_v1";
1393d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private static final int PREF_CONTACTS_IMPORT_VERSION = 1;
1403d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1410e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff    private static final String AGGREGATE_CONTACTS = "sync.contacts.aggregate";
1420e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff
143a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
1444f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
145d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, "
146d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.TIMES_CONTACTED + " DESC, "
1479b43551f1ce33b79141772737a262ce609bd0cebMegha Joshi            + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
148d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar    private static final String STREQUENT_LIMIT =
149d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE "
150d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.STARRED + "=1) + 25";
151d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov
152d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS = 1000;
153d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS_ID = 1001;
1545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_LOOKUP = 1002;
1555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_LOOKUP_ID = 1003;
1565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_DATA = 1004;
1575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_FILTER = 1005;
1585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_STREQUENT = 1006;
1595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_STREQUENT_FILTER = 1007;
1605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_GROUP = 1008;
1615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_PHOTO = 1009;
1624f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1635ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS = 2002;
1645ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_ID = 2003;
1655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_DATA = 2004;
1664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1676bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA = 3000;
1686bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA_ID = 3001;
169ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int PHONES = 3002;
17048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int PHONES_ID = 3003;
17148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int PHONES_FILTER = 3004;
17248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS = 3005;
17348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS_ID = 3006;
17448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS_LOOKUP = 3007;
17548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS_FILTER = 3008;
17648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int POSTALS = 3009;
17748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int POSTALS_ID = 3010;
178a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1796bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int PHONE_LOOKUP = 4000;
1806bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
181b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTIONS = 6000;
182b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTION_ID = 6001;
183b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
18482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    private static final int STATUS_UPDATES = 7000;
18582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    private static final int STATUS_UPDATES_ID = 7001;
1861f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
18731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    private static final int AGGREGATION_SUGGESTIONS = 8000;
18831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
189eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    private static final int SETTINGS = 9000;
190eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
191ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS = 10000;
192ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_ID = 10001;
193ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_SUMMARY = 10003;
194ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
19535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana    private static final int SYNCSTATE = 11000;
196b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private static final int SYNCSTATE_ID = 11001;
19735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
198c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SUGGESTIONS = 12001;
199c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SHORTCUT = 12002;
200c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2011b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS = 14000;
2021b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_WITH_PHONES = 14001;
2031b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002;
2041b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003;
2051b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
20667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    private interface ContactsQuery {
2075ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final String TABLE = Tables.RAW_CONTACTS;
2089261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
20967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
2106cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
2116cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.ACCOUNT_NAME,
2126cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.ACCOUNT_TYPE,
213ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
214ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2155ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
21667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int ACCOUNT_NAME = 1;
21767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int ACCOUNT_TYPE = 2;
21867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    }
21967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
220d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private interface DataContactsQuery {
221d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS;
22267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
22367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
2246cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
2253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
226d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            ContactsColumns.CONCRETE_ID,
2273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.CONCRETE_ID,
228ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
229ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
230d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
23167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA_ID = 1;
232d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int CONTACT_ID = 2;
23367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int MIMETYPE_ID = 3;
234ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
2351f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private interface DisplayNameQuery {
23767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
2383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final String[] COLUMNS = new String[] {
2403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
2413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
242f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            Data.DATA1,
243a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            Organization.TITLE,
2443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
2453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 0;
2473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 1;
248a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        public static final int DATA = 2;
249a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        public static final int TITLE = 3;
2503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
2513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
25214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    private interface DataDeleteQuery {
25367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
2543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
25588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] CONCRETE_COLUMNS = new String[] {
2563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
2573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
2585ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Data.RAW_CONTACT_ID,
2593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
260f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            Data.DATA1,
26188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        };
26288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov
26388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] COLUMNS = new String[] {
26488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data._ID,
26588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            MimetypesColumns.MIMETYPE,
26688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.RAW_CONTACT_ID,
26788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.IS_PRIMARY,
268f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            Data.DATA1,
2693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
2703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
27114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public static final int _ID = 0;
2723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 1;
2735ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 2;
2743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 3;
275f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        public static final int DATA1 = 4;
2763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
2773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
27814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    private interface DataUpdateQuery {
279321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        String[] COLUMNS = { Data._ID, Data.RAW_CONTACT_ID, Data.MIMETYPE };
28020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
28120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int _ID = 0;
282321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int RAW_CONTACT_ID = 1;
283321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int MIMETYPE = 2;
28420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
28520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
286f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
287f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private interface NicknameLookupQuery {
288f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        String TABLE = Tables.NICKNAME_LOOKUP;
289f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
290f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        String[] COLUMNS = new String[] {
291f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            NicknameLookupColumns.CLUSTER
292f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        };
293f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
294f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        int CLUSTER = 0;
295f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
296f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
29719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka    private interface RawContactsQuery {
29819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        String TABLE = Tables.RAW_CONTACTS;
29919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka
30019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        String[] COLUMNS = new String[] {
30119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                ContactsContract.RawContacts.DELETED
30219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        };
30319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka
30419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        int DELETED = 0;
30519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka    }
30619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka
30725abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov    private static final HashMap<String, Integer> sDisplayNameSources;
3083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    static {
30925abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        sDisplayNameSources = new HashMap<String, Integer>();
31025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        sDisplayNameSources.put(StructuredName.CONTENT_ITEM_TYPE,
31125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                DisplayNameSources.STRUCTURED_NAME);
312a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        sDisplayNameSources.put(Nickname.CONTENT_ITEM_TYPE,
313a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                DisplayNameSources.NICKNAME);
31425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        sDisplayNameSources.put(Organization.CONTENT_ITEM_TYPE,
31525abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                DisplayNameSources.ORGANIZATION);
31625abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        sDisplayNameSources.put(Phone.CONTENT_ITEM_TYPE,
31725abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                DisplayNameSources.PHONE);
31825abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        sDisplayNameSources.put(Email.CONTENT_ITEM_TYPE,
31925abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                DisplayNameSources.EMAIL);
3203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
32131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
322caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    public static final String DEFAULT_ACCOUNT_TYPE = "com.google.GAIA";
323df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana    public static final String FEATURE_LEGACY_HOSTED_OR_GOOGLE = "legacy_hosted_or_google";
324caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
32571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov    /** Sql where statement for filtering on groups. */
32671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov    private static final String CONTACTS_IN_GROUP_SELECT =
32771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov            Contacts._ID + " IN "
32871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    + "(SELECT " + RawContacts.CONTACT_ID
32971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    + " FROM " + Tables.RAW_CONTACTS
33071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN "
33171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                            + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID
33271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                            + " FROM " + Tables.DATA_JOIN_MIMETYPES
33371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                            + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE
33471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + "' AND " + GroupMembership.GROUP_ROW_ID + "="
33571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + "(SELECT " + Tables.GROUPS + "." + Groups._ID
33671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + " FROM " + Tables.GROUPS
33771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + " WHERE " + Groups.TITLE + "=?)))";
33871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov
339038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana    /** Contains just BaseColumns._COUNT */
340038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana    private static final HashMap<String, String> sCountProjectionMap;
341e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov    /** Contains just the contacts columns */
3424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    private static final HashMap<String, String> sContactsProjectionMap;
343ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    /** Contains just the raw contacts columns */
344d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final HashMap<String, String> sRawContactsProjectionMap;
3454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /** Contains columns from the data view */
3464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final HashMap<String, String> sDataProjectionMap;
3475e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    /** Contains columns from the data view */
3485e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    private static final HashMap<String, String> sDistinctDataProjectionMap;
3499261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /** Contains the data and contacts columns, for joined tables */
350e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov    private static final HashMap<String, String> sPhoneLookupProjectionMap;
351ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains the just the {@link Groups} columns */
352ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsProjectionMap;
353ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains {@link Groups} columns along with summary details */
354ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsSummaryProjectionMap;
355373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    /** Contains the agg_exceptions columns */
356b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final HashMap<String, String> sAggregationExceptionsProjectionMap;
357eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    /** Contains the agg_exceptions columns */
358eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    private static final HashMap<String, String> sSettingsProjectionMap;
35982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    /** Contains StatusUpdates columns */
36082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    private static final HashMap<String, String> sStatusUpdatesProjectionMap;
3611b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    /** Contains Live Folders columns */
3621b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final HashMap<String, String> sLiveFoldersProjectionMap;
3637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
364c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Precompiled sql statement for setting a data record to the primary. */
365c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetPrimaryStatement;
3663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for setting a data record to the super primary. */
367c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetSuperPrimaryStatement;
368d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Precompiled sql statement for incrementing times contacted for an contact */
369f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private SQLiteStatement mLastTimeContactedUpdate;
3703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for updating a contact display name */
37125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov    private SQLiteStatement mRawContactDisplayNameUpdate;
37273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /** Precompiled sql statement for marking a raw contact as dirty */
37373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private SQLiteStatement mRawContactDirtyUpdate;
37482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    /** Precompiled sql statement for updating an aggregated status update */
375a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov    private SQLiteStatement mLastStatusUpdate;
376f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private SQLiteStatement mNameLookupInsert;
377f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private SQLiteStatement mNameLookupDelete;
378a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov    private SQLiteStatement mStatusUpdateAutoTimestamp;
379a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov    private SQLiteStatement mStatusUpdateInsert;
380a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov    private SQLiteStatement mStatusUpdateReplace;
381a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov    private SQLiteStatement mStatusUpdateDelete;
382a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
3834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    static {
3844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        // Contacts URI matching table
385a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final UriMatcher matcher = sUriMatcher;
386d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS);
387d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
388d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_DATA);
3893653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions",
3903653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                AGGREGATION_SUGGESTIONS);
3912d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*",
3922d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                AGGREGATION_SUGGESTIONS);
3933653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_PHOTO);
3945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER);
3955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP);
3965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID);
3975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT);
398ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*",
399ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                CONTACTS_STREQUENT_FILTER);
4005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP);
4013653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
4025ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
4035ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID);
4045ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA);
405b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
4064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);
4074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID);
408ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES);
40948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID);
4105e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER);
411ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER);
4124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS);
41348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID);
4145e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP);
4155e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER);
4164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER);
417ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS);
41848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID);
4191f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
420ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS);
421ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID);
422ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY);
423ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
42435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE);
425b5a4add17815167d20a90645779df34cdf45280dFred Quintana        matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#",
426b5a4add17815167d20a90645779df34cdf45280dFred Quintana                SYNCSTATE_ID);
42735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
428a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP);
429b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions",
430b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTIONS);
431b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*",
432b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTION_ID);
4334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
434eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS);
435eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
43682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES);
43782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID);
4381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
439c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
440c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
441c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
442c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
443c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/#",
444c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SHORTCUT);
445c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
4461b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts",
4471b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS);
4481b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*",
4491b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_GROUP_NAME);
4501b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones",
4511b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_WITH_PHONES);
4521b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites",
4531b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_FAVORITES);
45419a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov    }
45519a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
45619a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov    static {
457038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        sCountProjectionMap = new HashMap<String, String>();
458038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        sCountProjectionMap.put(BaseColumns._COUNT, "COUNT(*)");
459e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
4604a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap = new HashMap<String, String>();
4614a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts._ID, Contacts._ID);
4624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME);
4634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
4644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
4654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
4664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.IN_VISIBLE_GROUP, Contacts.IN_VISIBLE_GROUP);
4674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
4684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
469f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov        sContactsProjectionMap.put(Contacts.HAS_PHONE_NUMBER, Contacts.HAS_PHONE_NUMBER);
4704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
4715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sContactsProjectionMap.put(Contacts.LOOKUP_KEY, Contacts.LOOKUP_KEY);
472d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        sContactsProjectionMap.put(OpenableColumns.DISPLAY_NAME, Contacts.DISPLAY_NAME
473d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                + " || '.vcf' AS " + OpenableColumns.DISPLAY_NAME);
474d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        sContactsProjectionMap.put(OpenableColumns.SIZE, "0 AS " + OpenableColumns.SIZE);
47582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sContactsProjectionMap.put(Contacts.CONTACT_PRESENCE,
47682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE
47782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                        + " AS " + Contacts.CONTACT_PRESENCE);
47882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sContactsProjectionMap.put(Contacts.CONTACT_STATUS,
479a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                StatusUpdatesColumns.STATUS
48082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                        + " AS " + Contacts.CONTACT_STATUS);
48182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sContactsProjectionMap.put(Contacts.CONTACT_STATUS_TIMESTAMP,
482a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                StatusUpdatesColumns.TIMESTAMP
48382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                        + " AS " + Contacts.CONTACT_STATUS_TIMESTAMP);
4844a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
4854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap = new HashMap<String, String>();
4864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts._ID, RawContacts._ID);
4874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
4884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
4894a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
4904a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
4914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.VERSION, RawContacts.VERSION);
4924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DIRTY, RawContacts.DIRTY);
4934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DELETED, RawContacts.DELETED);
4944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.TIMES_CONTACTED, RawContacts.TIMES_CONTACTED);
4954a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.LAST_TIME_CONTACTED,
4964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                RawContacts.LAST_TIME_CONTACTED);
4974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.CUSTOM_RINGTONE, RawContacts.CUSTOM_RINGTONE);
4984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SEND_TO_VOICEMAIL, RawContacts.SEND_TO_VOICEMAIL);
4994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.STARRED, RawContacts.STARRED);
5004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE);
5014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC1, RawContacts.SYNC1);
5024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC2, RawContacts.SYNC2);
5034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC3, RawContacts.SYNC3);
5044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC4, RawContacts.SYNC4);
5052815f58f72f109790585931f601a63ddc02536a5Evan Millar
5064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap = new HashMap<String, String>();
5074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data._ID, Data._ID);
5084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.RAW_CONTACT_ID, Data.RAW_CONTACT_ID);
5094a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA_VERSION, Data.DATA_VERSION);
5104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.IS_PRIMARY, Data.IS_PRIMARY);
5114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY);
5124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.RES_PACKAGE, Data.RES_PACKAGE);
5134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.MIMETYPE, Data.MIMETYPE);
5144a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA1, Data.DATA1);
5154a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA2, Data.DATA2);
5164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA3, Data.DATA3);
5174a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA4, Data.DATA4);
5184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA5, Data.DATA5);
5194a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA6, Data.DATA6);
5204a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA7, Data.DATA7);
5214a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA8, Data.DATA8);
5224a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA9, Data.DATA9);
5234a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA10, Data.DATA10);
5244a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA11, Data.DATA11);
5254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA12, Data.DATA12);
5264a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA13, Data.DATA13);
5274a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA14, Data.DATA14);
5284a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA15, Data.DATA15);
5294a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC1, Data.SYNC1);
5304a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC2, Data.SYNC2);
5314a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC3, Data.SYNC3);
5324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC4, Data.SYNC4);
53382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sDataProjectionMap.put(Data.CONTACT_ID, Data.CONTACT_ID);
5344a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
5354a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
5364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
5374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.VERSION, RawContacts.VERSION);
5384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.DIRTY, RawContacts.DIRTY);
53956d2bd40ebb238c2990bc239f68c7e61c7d5b02cEvan Millar        sDataProjectionMap.put(Contacts.LOOKUP_KEY, Contacts.LOOKUP_KEY);
5404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME);
5414a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
5424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
5434a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
5444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
5454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
5464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
54782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sDataProjectionMap.put(Contacts.CONTACT_PRESENCE,
54882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                StatusUpdates.PRESENCE + " AS " + Contacts.CONTACT_PRESENCE);
54982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sDataProjectionMap.put(Contacts.CONTACT_STATUS,
55082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                StatusUpdatesColumns.STATUS + " AS " + Contacts.CONTACT_STATUS);
55182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sDataProjectionMap.put(Contacts.CONTACT_STATUS_TIMESTAMP,
55282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                StatusUpdatesColumns.TIMESTAMP + " AS " + Contacts.CONTACT_STATUS_TIMESTAMP);
5534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(GroupMembership.GROUP_SOURCE_ID, GroupMembership.GROUP_SOURCE_ID);
554a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
5555e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        // Projection map for data grouped by contact (not raw contact) and some data field(s)
5565e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap = new HashMap<String, String>();
5575e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data._ID,
5585e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                "MIN(" + Data._ID + ") AS " + Data._ID);
5595e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA_VERSION, Data.DATA_VERSION);
5605e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.IS_PRIMARY, Data.IS_PRIMARY);
5615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY);
5625e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.RES_PACKAGE, Data.RES_PACKAGE);
5635e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.MIMETYPE, Data.MIMETYPE);
5645e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA1, Data.DATA1);
5655e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA2, Data.DATA2);
5665e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA3, Data.DATA3);
5675e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA4, Data.DATA4);
5685e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA5, Data.DATA5);
5695e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA6, Data.DATA6);
5705e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA7, Data.DATA7);
5715e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA8, Data.DATA8);
5725e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA9, Data.DATA9);
5735e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA10, Data.DATA10);
5745e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA11, Data.DATA11);
5755e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA12, Data.DATA12);
5765e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA13, Data.DATA13);
5775e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA14, Data.DATA14);
5785e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.DATA15, Data.DATA15);
5795e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.SYNC1, Data.SYNC1);
5805e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.SYNC2, Data.SYNC2);
5815e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.SYNC3, Data.SYNC3);
5825e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Data.SYNC4, Data.SYNC4);
5835e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
5848f1631f8a610e7278526916ce73ac1e422a5c9b8Jeff Sharkey        sDistinctDataProjectionMap.put(Contacts.LOOKUP_KEY, Contacts.LOOKUP_KEY);
5855e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME);
5865e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
5875e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
5885e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
5895e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
5905e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
5915e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
59282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.CONTACT_PRESENCE,
59382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                StatusUpdates.PRESENCE + " AS " + Contacts.CONTACT_PRESENCE);
59482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.CONTACT_STATUS,
59582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                StatusUpdatesColumns.STATUS + " AS " + Contacts.CONTACT_STATUS);
59682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sDistinctDataProjectionMap.put(Contacts.CONTACT_STATUS_TIMESTAMP,
59782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                StatusUpdatesColumns.TIMESTAMP + " AS " + Contacts.CONTACT_STATUS_TIMESTAMP);
5985e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sDistinctDataProjectionMap.put(GroupMembership.GROUP_SOURCE_ID,
5995e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                GroupMembership.GROUP_SOURCE_ID);
6005e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
601e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap = new HashMap<String, String>();
602e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup._ID,
603e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_ID + " AS " + PhoneLookup._ID);
60456d2bd40ebb238c2990bc239f68c7e61c7d5b02cEvan Millar        sPhoneLookupProjectionMap.put(PhoneLookup.LOOKUP_KEY,
60556d2bd40ebb238c2990bc239f68c7e61c7d5b02cEvan Millar                Contacts.LOOKUP_KEY + " AS " + PhoneLookup.LOOKUP_KEY);
606e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.DISPLAY_NAME,
607e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_DISPLAY_NAME + " AS " + PhoneLookup.DISPLAY_NAME);
608e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.LAST_TIME_CONTACTED,
609e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_LAST_TIME_CONTACTED
610e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                        + " AS " + PhoneLookup.LAST_TIME_CONTACTED);
611e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.TIMES_CONTACTED,
612e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_TIMES_CONTACTED + " AS " + PhoneLookup.TIMES_CONTACTED);
613e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.STARRED,
614e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_STARRED + " AS " + PhoneLookup.STARRED);
615e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.IN_VISIBLE_GROUP,
616e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Contacts.IN_VISIBLE_GROUP + " AS " + PhoneLookup.IN_VISIBLE_GROUP);
617e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.PHOTO_ID,
618e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Contacts.PHOTO_ID + " AS " + PhoneLookup.PHOTO_ID);
619e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.CUSTOM_RINGTONE,
620e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_CUSTOM_RINGTONE + " AS " + PhoneLookup.CUSTOM_RINGTONE);
621e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.HAS_PHONE_NUMBER,
622e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Contacts.HAS_PHONE_NUMBER + " AS " + PhoneLookup.HAS_PHONE_NUMBER);
623e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.SEND_TO_VOICEMAIL,
624e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_SEND_TO_VOICEMAIL
625e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                        + " AS " + PhoneLookup.SEND_TO_VOICEMAIL);
626e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.NUMBER,
627e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.NUMBER + " AS " + PhoneLookup.NUMBER);
628e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.TYPE,
629e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.TYPE + " AS " + PhoneLookup.TYPE);
630e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.LABEL,
631e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.LABEL + " AS " + PhoneLookup.LABEL);
6329261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
633e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        HashMap<String, String> columns;
6347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
635ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Groups projection map
636ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
63789c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups._ID, Groups._ID);
638035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_NAME, Groups.ACCOUNT_NAME);
639035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_TYPE, Groups.ACCOUNT_TYPE);
6409261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.SOURCE_ID, Groups.SOURCE_ID);
6419261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.DIRTY, Groups.DIRTY);
6429261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.VERSION, Groups.VERSION);
64389c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups.RES_PACKAGE, Groups.RES_PACKAGE);
644ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.TITLE, Groups.TITLE);
64567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Groups.TITLE_RES, Groups.TITLE_RES);
646ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.GROUP_VISIBLE, Groups.GROUP_VISIBLE);
6473cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYSTEM_ID, Groups.SYSTEM_ID);
64894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        columns.put(Groups.DELETED, Groups.DELETED);
6493cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.NOTES, Groups.NOTES);
65038446bf47c5ee2080df69f5fc8a33ad2fa3e61b5Jeff Sharkey        columns.put(Groups.SHOULD_SYNC, Groups.SHOULD_SYNC);
65189c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups.SYNC1, Groups.SYNC1);
65289c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups.SYNC2, Groups.SYNC2);
65389c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups.SYNC3, Groups.SYNC3);
65489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov        columns.put(Groups.SYNC4, Groups.SYNC4);
655ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsProjectionMap = columns;
656ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
6576cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        // RawContacts and groups projection map
658ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
659ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.putAll(sGroupsProjectionMap);
660d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Groups.SUMMARY_COUNT, "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID
661d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
662ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
663ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + ") AS " + Groups.SUMMARY_COUNT);
664ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.SUMMARY_WITH_PHONES, "(SELECT COUNT(DISTINCT "
665d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ContactsColumns.CONCRETE_ID + ") FROM "
666d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
667ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
668f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov                + " AND " + Contacts.HAS_PHONE_NUMBER + ") AS " + Groups.SUMMARY_WITH_PHONES);
669ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsSummaryProjectionMap = columns;
670ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
671b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        // Aggregate exception projection map
672b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns = new HashMap<String, String>();
673b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id AS _id");
674b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE);
6750c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        columns.put(AggregationExceptions.RAW_CONTACT_ID1, AggregationExceptions.RAW_CONTACT_ID1);
6760c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        columns.put(AggregationExceptions.RAW_CONTACT_ID2, AggregationExceptions.RAW_CONTACT_ID2);
677b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        sAggregationExceptionsProjectionMap = columns;
678b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
679eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        // Settings projection map
680eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns = new HashMap<String, String>();
681eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.ACCOUNT_NAME, Settings.ACCOUNT_NAME);
682eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.ACCOUNT_TYPE, Settings.ACCOUNT_TYPE);
683eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.UNGROUPED_VISIBLE, Settings.UNGROUPED_VISIBLE);
684eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.SHOULD_SYNC, Settings.SHOULD_SYNC);
685341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey        columns.put(Settings.ANY_UNSYNCED, "(CASE WHEN MIN(" + Settings.SHOULD_SYNC
686341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey                + ",(SELECT (CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL THEN 1 ELSE MIN("
687341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey                + Groups.SHOULD_SYNC + ") END) FROM " + Tables.GROUPS + " WHERE "
688fc4e892529eccdfa42121f0304ec7d0dbb42d6c9Dmitri Plotnikov                + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" + SettingsColumns.CONCRETE_ACCOUNT_NAME
689341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey                + " AND " + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "="
690341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey                + SettingsColumns.CONCRETE_ACCOUNT_TYPE + "))=0 THEN 1 ELSE 0 END) AS "
691341e4621f2ee7614c66bc25dd3da70eaaa866b46Jeff Sharkey                + Settings.ANY_UNSYNCED);
69268936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey        columns.put(Settings.UNGROUPED_COUNT, "(SELECT COUNT(*) FROM (SELECT 1 FROM "
69368936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS + " GROUP BY "
69468936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID + " HAVING " + Clauses.HAVING_NO_GROUPS
69568936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + ")) AS " + Settings.UNGROUPED_COUNT);
69668936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey        columns.put(Settings.UNGROUPED_WITH_PHONES, "(SELECT COUNT(*) FROM (SELECT 1 FROM "
697e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS + " WHERE "
69868936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Contacts.HAS_PHONE_NUMBER + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID
69968936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + " HAVING " + Clauses.HAVING_NO_GROUPS + ")) AS "
70068936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Settings.UNGROUPED_WITH_PHONES);
701eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        sSettingsProjectionMap = columns;
702eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
703373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns = new HashMap<String, String>();
7044dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        columns.put(PresenceColumns.RAW_CONTACT_ID, PresenceColumns.RAW_CONTACT_ID);
70582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.DATA_ID, StatusUpdates.DATA_ID);
70682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.IM_ACCOUNT, StatusUpdates.IM_ACCOUNT);
70782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.IM_HANDLE, StatusUpdates.IM_HANDLE);
70882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.PROTOCOL, StatusUpdates.PROTOCOL);
70970c314fb9b2ef3d47340b93816d46200aba9f5ecDmitri Plotnikov        // We cannot allow a null in the custom protocol field, because SQLite3 does not
71070c314fb9b2ef3d47340b93816d46200aba9f5ecDmitri Plotnikov        // properly enforce uniqueness of null values
71182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.CUSTOM_PROTOCOL, "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL
71282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                + "='' THEN NULL ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END) AS "
71382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                + StatusUpdates.CUSTOM_PROTOCOL);
71482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.PRESENCE, StatusUpdates.PRESENCE);
71582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.STATUS,
71682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                StatusUpdatesColumns.STATUS + " AS " + StatusUpdates.STATUS);
71782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        columns.put(StatusUpdates.STATUS_TIMESTAMP,
71882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                StatusUpdatesColumns.TIMESTAMP + " AS " + StatusUpdates.STATUS_TIMESTAMP);
71982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sStatusUpdatesProjectionMap = columns;
72019a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
7211b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // Live folder projection
7221b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap = new HashMap<String, String>();
7231b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap.put(LiveFolders._ID,
7241b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                Contacts._ID + " AS " + LiveFolders._ID);
7251b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap.put(LiveFolders.NAME,
7261b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                Contacts.DISPLAY_NAME + " AS " + LiveFolders.NAME);
7271b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
7281b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // TODO: Put contact photo back when we have a way to display a default icon
7291b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // for contacts without a photo
7301b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // sLiveFoldersProjectionMap.put(LiveFolders.ICON_BITMAP,
7311b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        //      Photos.DATA + " AS " + LiveFolders.ICON_BITMAP);
7324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
7334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
7343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /**
7353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     * Handles inserts and update for a specific Data type.
7363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     */
7373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private abstract class DataRowHandler {
7383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected final String mMimetype;
740653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        protected long mMimetypeId;
7413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public DataRowHandler(String mimetype) {
7433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mMimetype = mimetype;
744a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka
745a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            // To ensure the data column position. This is dead code if properly configured.
746a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            if (StructuredName.DISPLAY_NAME != Data.DATA1 || Nickname.NAME != Data.DATA1
747a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    || Organization.COMPANY != Data.DATA1 || Phone.NUMBER != Data.DATA1
748a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    || Email.DATA != Data.DATA1) {
749a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                throw new AssertionError("Some of ContactsContract.CommonDataKinds class primary"
750a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                        + " data is not in DATA1 column");
751a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            }
7523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
754653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        protected long getMimeTypeId() {
755653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (mMimetypeId == 0) {
756653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                mMimetypeId = mOpenHelper.getMimeTypeId(mMimetype);
757653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
758653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return mMimetypeId;
759653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
760653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
7613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
7623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Inserts a row into the {@link Data} table.
7633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
7645ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
765e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            final long dataId = db.insert(Tables.DATA, null, values);
766e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
767e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            Integer primary = values.getAsInteger(Data.IS_PRIMARY);
768e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (primary != null && primary != 0) {
769653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, getMimeTypeId());
770e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
771e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
772e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return dataId;
7733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
7763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Validates data and updates a {@link Data} row using the cursor, which contains
7773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * the current data.
7783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
779653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
780f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
78114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
78214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
783653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
784653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (values.containsKey(Data.IS_SUPER_PRIMARY)) {
785653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                long mimeTypeId = getMimeTypeId();
786653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
787653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, mimeTypeId);
788653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
789653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                // Now that we've taken care of setting these, remove them from "values".
790653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_SUPER_PRIMARY);
791653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_PRIMARY);
792653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            } else if (values.containsKey(Data.IS_PRIMARY)) {
793653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, getMimeTypeId());
794653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
795653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                // Now that we've taken care of setting this, remove it from "values".
796653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_PRIMARY);
797653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
798653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
799653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (values.size() > 0) {
800653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                mDb.update(Tables.DATA, values, Data._ID + " = " + dataId, null);
801653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
802653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
803f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            if (!callerIsSyncAdapter) {
804653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setRawContactDirty(rawContactId);
805653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
8063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
80914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
81014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
81114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            boolean primary = c.getInt(DataDeleteQuery.IS_PRIMARY) != 0;
8123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            int count = db.delete(Tables.DATA, Data._ID + "=" + dataId, null);
8133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (count != 0 && primary) {
8145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                fixPrimary(db, rawContactId);
8153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return count;
8173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8195ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        private void fixPrimary(SQLiteDatabase db, long rawContactId) {
8205ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long newPrimaryId = findNewPrimaryDataId(db, rawContactId);
8213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (newPrimaryId != -1) {
82214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                setIsPrimary(rawContactId, newPrimaryId, getMimeTypeId());
8233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8265ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected long findNewPrimaryDataId(SQLiteDatabase db, long rawContactId) {
827e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            long primaryId = -1;
828e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            int primaryType = -1;
8295ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Cursor c = queryData(db, rawContactId);
8303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
831e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                while (c.moveToNext()) {
83214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    long dataId = c.getLong(DataDeleteQuery._ID);
833f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                    int type = c.getInt(DataDeleteQuery.DATA1);
834e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) {
835e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryId = dataId;
836e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryType = type;
837e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    }
8383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
8393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
8403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
8413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
842e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return primaryId;
843e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
844e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
845e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        /**
846e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * Returns the rank of a specific record type to be used in determining the primary
847e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * row. Lower number represents higher priority.
848e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         */
849e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
850e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return 0;
8513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected Cursor queryData(SQLiteDatabase db, long rawContactId) {
85414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return db.query(DataDeleteQuery.TABLE, DataDeleteQuery.CONCRETE_COLUMNS,
85514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    Data.RAW_CONTACT_ID + "=" + rawContactId +
85614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    " AND " + MimetypesColumns.MIMETYPE + "='" + mMimetype + "'",
8573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    null, null, null, null);
8583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
86025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        protected void fixRawContactDisplayName(SQLiteDatabase db, long rawContactId) {
8613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String bestDisplayName = null;
86225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            int bestDisplayNameSource = DisplayNameSources.UNDEFINED;
86325abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov
86467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            Cursor c = db.query(DisplayNameQuery.TABLE, DisplayNameQuery.COLUMNS,
8655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    Data.RAW_CONTACT_ID + "=" + rawContactId, null, null, null, null);
8663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
8673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                while (c.moveToNext()) {
8683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    String mimeType = c.getString(DisplayNameQuery.MIMETYPE);
869a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka
870a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    // Display name is at DATA1 in all type.  This is ensured in the constructor.
871a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    String name = c.getString(DisplayNameQuery.DATA);
872a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    if (TextUtils.isEmpty(name)
873a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                            && Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
874a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                        name = c.getString(DisplayNameQuery.TITLE);
8753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    }
876a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    boolean primary = StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)
877a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                        || (c.getInt(DisplayNameQuery.IS_PRIMARY) != 0);
8783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
87901911fa9cfa21f198fd767eedde072acbb879f28Dmitri Plotnikov                    if (name != null) {
88025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                        Integer source = sDisplayNameSources.get(mimeType);
88101911fa9cfa21f198fd767eedde072acbb879f28Dmitri Plotnikov                        if (source != null
88201911fa9cfa21f198fd767eedde072acbb879f28Dmitri Plotnikov                                && (source > bestDisplayNameSource
88301911fa9cfa21f198fd767eedde072acbb879f28Dmitri Plotnikov                                        || (source == bestDisplayNameSource && primary))) {
88425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                            bestDisplayNameSource = source;
8853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                            bestDisplayName = name;
8863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        }
8873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    }
8883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
8893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
8913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
8923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
89425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            setDisplayName(rawContactId, bestDisplayName, bestDisplayNameSource);
895285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            if (!isNewRawContact(rawContactId)) {
896285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateDisplayName(db, rawContactId);
897285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
8983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
899a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
900a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
901a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return true;
902a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
903622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
904622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
905622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Return set of values, using current values at given {@link Data#_ID}
906622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * as baseline, but augmented with any updates.
907622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
908622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public ContentValues getAugmentedValues(SQLiteDatabase db, long dataId,
909622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                ContentValues update) {
910622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues values = new ContentValues();
911622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final Cursor cursor = db.query(Tables.DATA, null, Data._ID + "=" + dataId,
912622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                    null, null, null, null);
913622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            try {
914622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                if (cursor.moveToFirst()) {
915622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                    for (int i = 0; i < cursor.getColumnCount(); i++) {
916622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                        final String key = cursor.getColumnName(i);
917622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                        values.put(key, cursor.getString(i));
918622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                    }
919622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                }
920622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            } finally {
921622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                cursor.close();
922622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
923622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            values.putAll(update);
924622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            return values;
925622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
9263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
9273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CustomDataRowHandler extends DataRowHandler {
9293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CustomDataRowHandler(String mimetype) {
9313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
9323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
9343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class StructuredNameRowHandler extends DataRowHandler {
936622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private final NameSplitter mSplitter;
9373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
938622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public StructuredNameRowHandler(NameSplitter splitter) {
9393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(StructuredName.CONTENT_ITEM_TYPE);
940622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            mSplitter = splitter;
9413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
9445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
945622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredNameComponents(values, values);
94614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
94714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
94814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
949f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            String name = values.getAsString(StructuredName.DISPLAY_NAME);
950f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            insertNameLookupForStructuredName(rawContactId, dataId, name);
95125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
95214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
95314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
95414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
95514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
95614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
957f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
958622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long dataId = c.getLong(DataUpdateQuery._ID);
959622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
960cabac02a2416b495e030654accffcbb5ae526678Dmitri Plotnikov
961622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues augmented = getAugmentedValues(db, dataId, values);
962622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredNameComponents(augmented, values);
96314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
964f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
96514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
966f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            if (values.containsKey(StructuredName.DISPLAY_NAME)) {
967f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                String name = values.getAsString(StructuredName.DISPLAY_NAME);
968f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                deleteNameLookup(dataId);
969f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                insertNameLookupForStructuredName(rawContactId, dataId, name);
97014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            }
97125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
97214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
97314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
97414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
97514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
97614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
97714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
97814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
97914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
98014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
981f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            deleteNameLookup(dataId);
98225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
98314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
9843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
987622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Specific list of structured fields.
9883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
989622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private final String[] STRUCTURED_FIELDS = new String[] {
990622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredName.PREFIX, StructuredName.GIVEN_NAME, StructuredName.MIDDLE_NAME,
991622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredName.FAMILY_NAME, StructuredName.SUFFIX
992622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        };
9933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
994622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
995622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Parses the supplied display name, but only if the incoming values do
996622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * not already contain structured name parts. Also, if the display name
997622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * is not provided, generate one by concatenating first name and last
998622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * name.
999622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1000622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private void fixStructuredNameComponents(ContentValues augmented, ContentValues update) {
1001622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final String unstruct = update.getAsString(StructuredName.DISPLAY_NAME);
1002622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1003622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final boolean touchedUnstruct = !TextUtils.isEmpty(unstruct);
1004622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final boolean touchedStruct = !areAllEmpty(update, STRUCTURED_FIELDS);
1005622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1006622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            if (touchedUnstruct && !touchedStruct) {
10078c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                NameSplitter.Name name = new NameSplitter.Name();
1008622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                mSplitter.split(name, unstruct);
1009622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                name.toValues(update);
1010622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            } else if (!touchedUnstruct && touchedStruct) {
10118c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                NameSplitter.Name name = new NameSplitter.Name();
1012622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                name.fromValues(augmented);
1013622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                final String joined = mSplitter.join(name);
1014622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                update.put(StructuredName.DISPLAY_NAME, joined);
1015622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
1016622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1017622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    }
1018622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1019622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    public class StructuredPostalRowHandler extends DataRowHandler {
1020622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private PostalSplitter mSplitter;
1021622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1022622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public StructuredPostalRowHandler(PostalSplitter splitter) {
1023622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            super(StructuredPostal.CONTENT_ITEM_TYPE);
1024622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            mSplitter = splitter;
1025622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1026622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1027622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        @Override
1028622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1029622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredPostalComponents(values, values);
1030622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            return super.insert(db, rawContactId, values);
1031622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1032622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1033622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        @Override
1034622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1035f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
1036622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long dataId = c.getLong(DataUpdateQuery._ID);
1037622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues augmented = getAugmentedValues(db, dataId, values);
1038622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredPostalComponents(augmented, values);
1039f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
1040622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1041622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1042622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1043622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Specific list of structured fields.
1044622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1045622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private final String[] STRUCTURED_FIELDS = new String[] {
1046622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredPostal.STREET, StructuredPostal.POBOX, StructuredPostal.NEIGHBORHOOD,
1047622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredPostal.CITY, StructuredPostal.REGION, StructuredPostal.POSTCODE,
1048622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredPostal.COUNTRY,
1049622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        };
1050622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1051622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1052622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Prepares the given {@link StructuredPostal} row, building
1053622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * {@link StructuredPostal#FORMATTED_ADDRESS} to match the structured
1054622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * values when missing. When structured components are missing, the
1055622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * unstructured value is assigned to {@link StructuredPostal#STREET}.
1056622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1057622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private void fixStructuredPostalComponents(ContentValues augmented, ContentValues update) {
1058622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final String unstruct = update.getAsString(StructuredPostal.FORMATTED_ADDRESS);
1059622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1060622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final boolean touchedUnstruct = !TextUtils.isEmpty(unstruct);
1061622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final boolean touchedStruct = !areAllEmpty(update, STRUCTURED_FIELDS);
1062622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1063622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final PostalSplitter.Postal postal = new PostalSplitter.Postal();
1064622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1065622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            if (touchedUnstruct && !touchedStruct) {
1066622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                mSplitter.split(postal, unstruct);
1067622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                postal.toValues(update);
1068622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            } else if (!touchedUnstruct && touchedStruct) {
1069622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                postal.fromValues(augmented);
1070622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                final String joined = mSplitter.join(postal);
1071622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                update.put(StructuredPostal.FORMATTED_ADDRESS, joined);
10723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
10733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
10743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
10753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CommonDataRowHandler extends DataRowHandler {
10773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mTypeColumn;
10793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mLabelColumn;
10803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CommonDataRowHandler(String mimetype, String typeColumn, String labelColumn) {
10823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
10833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mTypeColumn = typeColumn;
10843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mLabelColumn = labelColumn;
10853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
10863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
10885ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1089622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            enforceTypeAndLabel(values, values);
1090622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            return super.insert(db, rawContactId, values);
1091622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
10923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1093622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        @Override
1094622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1095f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
1096622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long dataId = c.getLong(DataUpdateQuery._ID);
1097622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues augmented = getAugmentedValues(db, dataId, values);
1098622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            enforceTypeAndLabel(augmented, values);
1099f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
1100622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
11013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1102622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1103622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * If the given {@link ContentValues} defines {@link #mTypeColumn},
1104622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * enforce that {@link #mLabelColumn} only appears when type is
1105622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * {@link BaseTypes#TYPE_CUSTOM}. Exception is thrown otherwise.
1106622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1107622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private void enforceTypeAndLabel(ContentValues augmented, ContentValues update) {
1108622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final boolean hasType = !TextUtils.isEmpty(augmented.getAsString(mTypeColumn));
1109622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final boolean hasLabel = !TextUtils.isEmpty(augmented.getAsString(mLabelColumn));
11103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1111622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            if (hasLabel && !hasType) {
1112622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                // When label exists, assert that some type is defined
1113622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                throw new IllegalArgumentException(mTypeColumn + " must be specified when "
1114622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                        + mLabelColumn + " is defined.");
1115622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
11163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
11173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
11183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class OrganizationDataRowHandler extends CommonDataRowHandler {
11203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public OrganizationDataRowHandler() {
11223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Organization.CONTENT_ITEM_TYPE, Organization.TYPE, Organization.LABEL);
11233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
11243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
11265ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1127a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            String company = values.getAsString(Organization.COMPANY);
1128a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            String title = values.getAsString(Organization.TITLE);
1129a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka
1130a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            long dataId = super.insert(db, rawContactId, values);
1131a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka
113225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
1133a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            insertNameLookupForOrganization(rawContactId, dataId, company, title);
1134a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            return dataId;
11353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
11363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
113814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1139f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
1140a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            String company = values.getAsString(Organization.COMPANY);
1141a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            String title = values.getAsString(Organization.TITLE);
1142a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            long dataId = c.getLong(DataUpdateQuery._ID);
114314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
114414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1145f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
114614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
114725abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
1148a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            deleteNameLookup(dataId);
1149a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            insertNameLookupForOrganization(rawContactId, dataId, company, title);
115014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
115114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
115214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
115314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
1154a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            long dataId = c.getLong(DataUpdateQuery._ID);
115514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
115614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
115714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
115825abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
1159a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            deleteNameLookup(dataId);
116014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
116114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
116214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
116314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
11643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
11653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
11663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_WORK: return 0;
11673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_CUSTOM: return 1;
11683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_OTHER: return 2;
11693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
11703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
11713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
1172a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1173a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1174a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
1175a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return false;
1176a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
11773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
11783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1179e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    public class EmailDataRowHandler extends CommonDataRowHandler {
1180e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1181e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public EmailDataRowHandler() {
1182e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            super(Email.CONTENT_ITEM_TYPE, Email.TYPE, Email.LABEL);
1183e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1184e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1185e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
11865ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
118714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String address = values.getAsString(Email.DATA);
118814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
118914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
119014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
119125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
1192f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            insertNameLookupForEmail(rawContactId, dataId, address);
119314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
119414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
119514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
119614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
119714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1198f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
119914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
120014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
120114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String address = values.getAsString(Email.DATA);
120214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1203f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
120414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1205f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            deleteNameLookup(dataId);
1206f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            insertNameLookupForEmail(rawContactId, dataId, address);
120725abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
120814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
120914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
121014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
121114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
121214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
121314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
121414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
121514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
121614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1217f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            deleteNameLookup(dataId);
121825abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
121914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
1220e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1221e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1222e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
1223e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
1224e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            switch (type) {
1225e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_HOME: return 0;
1226e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_WORK: return 1;
1227e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_CUSTOM: return 2;
1228e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_OTHER: return 3;
1229e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                default: return 1000;
1230e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
1231e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1232e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    }
1233e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
123414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    public class NicknameDataRowHandler extends CommonDataRowHandler {
123514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
123614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public NicknameDataRowHandler() {
123714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super(Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE, Nickname.LABEL);
123814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
123914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
124014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
124114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
124214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String nickname = values.getAsString(Nickname.NAME);
124314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
124414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
124514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
124625abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
1247f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            insertNameLookupForNickname(rawContactId, dataId, nickname);
124814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
124914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
125014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
125114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
125214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1253f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
125414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
125514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
125614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String nickname = values.getAsString(Nickname.NAME);
125714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1258f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
125914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1260f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            deleteNameLookup(dataId);
1261f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            insertNameLookupForNickname(rawContactId, dataId, nickname);
126225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
126314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
126414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
126514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
126614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
126714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
126814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
126914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
127014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
127114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1272f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            deleteNameLookup(dataId);
127325abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
127414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
127514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
127614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    }
127714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
12783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class PhoneDataRowHandler extends CommonDataRowHandler {
12793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public PhoneDataRowHandler() {
12813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Phone.CONTENT_ITEM_TYPE, Phone.TYPE, Phone.LABEL);
12823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
12833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
12855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
12860b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            long dataId;
12870b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            if (values.containsKey(Phone.NUMBER)) {
12880b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String number = values.getAsString(Phone.NUMBER);
12890b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String normalizedNumber = computeNormalizedNumber(number, values);
1290653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
12910b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                dataId = super.insert(db, rawContactId, values);
1292653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
12930b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
1294285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateHasPhoneNumber(db, rawContactId);
129525abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                fixRawContactDisplayName(db, rawContactId);
12960b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            } else {
12970b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                dataId = super.insert(db, rawContactId, values);
12980b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            }
1299653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return dataId;
1300653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1301653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1302653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1303653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1304f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
130514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
130614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
13070b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            if (values.containsKey(Phone.NUMBER)) {
13080b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String number = values.getAsString(Phone.NUMBER);
13090b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String normalizedNumber = computeNormalizedNumber(number, values);
1310653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1311f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                super.update(db, values, c, callerIsSyncAdapter);
1312653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
13130b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
1314285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateHasPhoneNumber(db, rawContactId);
131525abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                fixRawContactDisplayName(db, rawContactId);
13160b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            } else {
1317f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                super.update(db, values, c, callerIsSyncAdapter);
13180b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            }
131914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
132014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
132114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
132214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
132314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
132414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
132514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
132614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
132714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
132814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            updatePhoneLookup(db, rawContactId, dataId, null, null);
1329285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            mContactAggregator.updateHasPhoneNumber(db, rawContactId);
133025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
133114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
1332653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1333653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1334653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        private String computeNormalizedNumber(String number, ContentValues values) {
1335e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            String normalizedNumber = null;
1336e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (number != null) {
1337e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                normalizedNumber = PhoneNumberUtils.getStrippedReversed(number);
1338e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
1339653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            values.put(PhoneColumns.NORMALIZED_NUMBER, normalizedNumber);
1340653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return normalizedNumber;
1341653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1342e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1343653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        private void updatePhoneLookup(SQLiteDatabase db, long rawContactId, long dataId,
1344653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                String number, String normalizedNumber) {
1345e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (number != null) {
1346653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                ContentValues phoneValues = new ContentValues();
13475ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.RAW_CONTACT_ID, rawContactId);
1348653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.DATA_ID, dataId);
1349e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, normalizedNumber);
1350653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                db.replace(Tables.PHONE_LOOKUP, null, phoneValues);
1351653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            } else {
1352653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                db.delete(Tables.PHONE_LOOKUP, PhoneLookupColumns.DATA_ID + "=" + dataId, null);
1353e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
13543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
13553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
13563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
13573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
13583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
13593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_MOBILE: return 0;
13603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_WORK: return 1;
13613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_HOME: return 2;
13623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_PAGER: return 3;
13633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_CUSTOM: return 4;
13643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_OTHER: return 5;
13653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_WORK: return 6;
13663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_HOME: return 7;
13673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
13683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
13693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
13703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
13713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1372653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    public class GroupMembershipRowHandler extends DataRowHandler {
1373653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1374653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public GroupMembershipRowHandler() {
1375653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            super(GroupMembership.CONTENT_ITEM_TYPE);
1376653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1377653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1378653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1379653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1380653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            resolveGroupSourceIdInValues(rawContactId, db, values, true);
13810be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
13820be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            updateVisibility(rawContactId);
13830be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            return dataId;
1384653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1385653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1386653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1387653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1388f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
138914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1390653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            resolveGroupSourceIdInValues(rawContactId, db, values, false);
1391f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
13920be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            updateVisibility(rawContactId);
13930be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        }
13940be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov
13950be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        @Override
13960be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
13970be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
13980be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            int count = super.delete(db, c);
13990be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            updateVisibility(rawContactId);
14000be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            return count;
14010be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        }
14020be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov
14030be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        private void updateVisibility(long rawContactId) {
14040be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            long contactId = mOpenHelper.getContactId(rawContactId);
14050be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            if (contactId != 0) {
14060be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov                mOpenHelper.updateContactVisible(contactId);
14070be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            }
1408653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1409653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1410653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        private void resolveGroupSourceIdInValues(long rawContactId, SQLiteDatabase db,
1411653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                ContentValues values, boolean isInsert) {
1412653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            boolean containsGroupSourceId = values.containsKey(GroupMembership.GROUP_SOURCE_ID);
1413653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            boolean containsGroupId = values.containsKey(GroupMembership.GROUP_ROW_ID);
1414653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (containsGroupSourceId && containsGroupId) {
1415653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                throw new IllegalArgumentException(
1416653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        "you are not allowed to set both the GroupMembership.GROUP_SOURCE_ID "
1417653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                + "and GroupMembership.GROUP_ROW_ID");
1418653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1419653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1420653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (!containsGroupSourceId && !containsGroupId) {
1421653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                if (isInsert) {
1422653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                    throw new IllegalArgumentException(
1423653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                            "you must set exactly one of GroupMembership.GROUP_SOURCE_ID "
1424653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                    + "and GroupMembership.GROUP_ROW_ID");
1425653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                } else {
1426653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                    return;
1427653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                }
1428653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1429653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1430653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (containsGroupSourceId) {
1431653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                final String sourceId = values.getAsString(GroupMembership.GROUP_SOURCE_ID);
1432653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                final long groupId = getOrMakeGroup(db, rawContactId, sourceId);
1433653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(GroupMembership.GROUP_SOURCE_ID);
1434653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.put(GroupMembership.GROUP_ROW_ID, groupId);
1435653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1436653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1437a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1438a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1439a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
1440a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return false;
1441a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1442653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    }
1443653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1444a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov    public class PhotoDataRowHandler extends DataRowHandler {
1445a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1446a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public PhotoDataRowHandler() {
1447a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            super(Photo.CONTENT_ITEM_TYPE);
1448a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1449a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1450a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1451a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1452a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
1453285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            if (!isNewRawContact(rawContactId)) {
1454285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updatePhotoId(db, rawContactId);
1455285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
1456a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return dataId;
1457a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1458a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1459a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1460a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1461f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                boolean callerIsSyncAdapter) {
1462a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1463f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            super.update(db, values, c, callerIsSyncAdapter);
1464a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            mContactAggregator.updatePhotoId(db, rawContactId);
1465a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1466a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1467a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1468a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
1469a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
1470a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            int count = super.delete(db, c);
1471a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            mContactAggregator.updatePhotoId(db, rawContactId);
1472a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return count;
1473a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1474a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1475a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1476a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
1477a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return false;
1478a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1479a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov    }
1480a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1481a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
14823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private HashMap<String, DataRowHandler> mDataRowHandlers;
148353056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov    private final ContactAggregationScheduler mAggregationScheduler;
14844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    private OpenHelper mOpenHelper;
148531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
14864097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov    private NameSplitter mNameSplitter;
1487f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private NameLookupBuilder mNameLookupBuilder;
1488f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private HashMap<String, SoftReference<String[]>> mNicknameClusterCache =
1489f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            new HashMap<String, SoftReference<String[]>>();
1490622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    private PostalSplitter mPostalSplitter;
1491622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1492622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    private ContactAggregator mContactAggregator;
1493f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private LegacyApiSupport mLegacyApiSupport;
1494a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    private GlobalSearchSupport mGlobalSearchSupport;
1495a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
149620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private ContentValues mValues = new ContentValues();
149720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1498ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov    private volatile CountDownLatch mAccessLatch;
149973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private boolean mImportMode;
150073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1501b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private HashSet<Long> mInsertedRawContacts = Sets.newHashSet();
1502b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private HashSet<Long> mUpdatedRawContacts = Sets.newHashSet();
1503b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private HashMap<Long, Object> mUpdatedSyncStates = Maps.newHashMap();
1504de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov
15051a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey    private boolean mVisibleTouched = false;
15061a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey
150781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov    private boolean mSyncToNetwork;
150881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov
1509a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    public ContactsProvider2() {
151053056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        this(new ContactAggregationScheduler());
1511a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1512a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1513a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
1514a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Constructor for testing.
1515a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
151653056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov    /* package */ ContactsProvider2(ContactAggregationScheduler scheduler) {
151753056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        mAggregationScheduler = scheduler;
1518a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
15194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
15204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
15214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public boolean onCreate() {
1522de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        super.onCreate();
152335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1524de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final Context context = getContext();
1525de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mOpenHelper = (OpenHelper)getOpenHelper();
1526a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mGlobalSearchSupport = new GlobalSearchSupport(this);
1527a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mLegacyApiSupport = new LegacyApiSupport(context, mOpenHelper, this, mGlobalSearchSupport);
1528cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov        mContactAggregator = new ContactAggregator(this, mOpenHelper, mAggregationScheduler);
15290e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff        mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true));
1530a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1531d51a83ac4f8032b62d9a23b90a8f43d6b7eb2dbbDmitri Plotnikov        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1532653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1533c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement = db.compileStatement(
1534653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "UPDATE " + Tables.DATA +
1535653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " SET " + Data.IS_PRIMARY + "=(_id=?)" +
1536653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " WHERE " + DataColumns.MIMETYPE_ID + "=?" +
1537653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "   AND " + Data.RAW_CONTACT_ID + "=?");
1538653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1539c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement = db.compileStatement(
1540653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "UPDATE " + Tables.DATA +
1541653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " SET " + Data.IS_SUPER_PRIMARY + "=(" + Data._ID + "=?)" +
1542653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " WHERE " + DataColumns.MIMETYPE_ID + "=?" +
1543653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "   AND " + Data.RAW_CONTACT_ID + " IN (" +
1544653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        "SELECT " + RawContacts._ID +
1545653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        " FROM " + Tables.RAW_CONTACTS +
1546653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        " WHERE " + RawContacts.CONTACT_ID + " =(" +
1547653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                "SELECT " + RawContacts.CONTACT_ID +
1548653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                " FROM " + Tables.RAW_CONTACTS +
1549653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                " WHERE " + RawContacts._ID + "=?))");
1550653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
15515ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mLastTimeContactedUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
15526cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                + RawContacts.TIMES_CONTACTED + "=" + RawContacts.TIMES_CONTACTED + "+1,"
1553d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + RawContacts.LAST_TIME_CONTACTED + "=? WHERE " + RawContacts.CONTACT_ID + "=?");
1554a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
155525abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        mRawContactDisplayNameUpdate = db.compileStatement(
155625abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                "UPDATE " + Tables.RAW_CONTACTS +
155725abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                " SET " + RawContactsColumns.DISPLAY_NAME + "=?,"
155825abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                        + RawContactsColumns.DISPLAY_NAME_SOURCE + "=?" +
155925abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                " WHERE " + RawContacts._ID + "=?");
15603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
156173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
156273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                + RawContacts.DIRTY + "=1 WHERE " + RawContacts._ID + "=?");
156373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1564a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        mLastStatusUpdate = db.compileStatement(
1565a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                "UPDATE " + Tables.CONTACTS
1566a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                + " SET " + ContactsColumns.LAST_STATUS_UPDATE_ID + "=" +
1567a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        "(SELECT " + DataColumns.CONCRETE_ID +
1568a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        " FROM " + Tables.STATUS_UPDATES +
1569a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        " JOIN " + Tables.DATA +
1570a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        "   ON (" + StatusUpdatesColumns.DATA_ID + "="
1571a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                                + DataColumns.CONCRETE_ID + ")" +
1572a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        " JOIN " + Tables.RAW_CONTACTS +
1573a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        "   ON (" + DataColumns.CONCRETE_RAW_CONTACT_ID + "="
1574a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                                + RawContactsColumns.CONCRETE_ID + ")" +
1575a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        " WHERE " + RawContacts.CONTACT_ID + "=?" +
1576a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        " ORDER BY " + StatusUpdatesColumns.TIMESTAMP + " DESC" +
1577a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        " LIMIT 1)"
1578a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                + " WHERE " + ContactsColumns.CONCRETE_ID + "=?");
1579e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
1580622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        final Locale locale = Locale.getDefault();
158128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar        mNameSplitter = new NameSplitter(
158228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_prefixes),
158328f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_last_name_prefixes),
158428f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_suffixes),
1585622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                context.getString(com.android.internal.R.string.common_name_conjunctions),
1586622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                locale);
1587f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter);
1588622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        mPostalSplitter = new PostalSplitter(locale);
15894097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
1590f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        mNameLookupInsert = db.compileStatement("INSERT OR IGNORE INTO " + Tables.NAME_LOOKUP + "("
1591f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                + NameLookupColumns.RAW_CONTACT_ID + "," + NameLookupColumns.DATA_ID + ","
1592f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                + NameLookupColumns.NAME_TYPE + "," + NameLookupColumns.NORMALIZED_NAME
1593f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                + ") VALUES (?,?,?,?)");
1594f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        mNameLookupDelete = db.compileStatement("DELETE FROM " + Tables.NAME_LOOKUP + " WHERE "
1595f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                + NameLookupColumns.DATA_ID + "=?");
1596f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
1597a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        mStatusUpdateInsert = db.compileStatement(
1598a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                "INSERT INTO " + Tables.STATUS_UPDATES + "("
1599a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        + StatusUpdatesColumns.DATA_ID + ", "
1600a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        + StatusUpdatesColumns.TIMESTAMP + ","
1601a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        + StatusUpdatesColumns.STATUS + ")" +
1602a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                " VALUES (?,?,?)");
1603a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
1604a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        mStatusUpdateReplace = db.compileStatement(
1605a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                "INSERT OR REPLACE INTO " + Tables.STATUS_UPDATES + "("
1606a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        + StatusUpdatesColumns.DATA_ID + ", "
1607a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        + StatusUpdatesColumns.TIMESTAMP + ","
1608a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        + StatusUpdatesColumns.STATUS + ")" +
1609a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                " VALUES (?,?,?)");
1610a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
1611a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        mStatusUpdateAutoTimestamp = db.compileStatement(
1612a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                "UPDATE " + Tables.STATUS_UPDATES +
1613a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                " SET " + StatusUpdatesColumns.TIMESTAMP + "=?,"
1614a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        + StatusUpdatesColumns.STATUS + "=?" +
1615a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                " WHERE " + StatusUpdatesColumns.DATA_ID + "=?"
1616a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        + " AND " + StatusUpdatesColumns.STATUS + "!=?");
1617a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
1618a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        mStatusUpdateDelete = db.compileStatement(
1619a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                "DELETE FROM " + Tables.STATUS_UPDATES +
1620a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                " WHERE " + StatusUpdatesColumns.DATA_ID + "=?");
1621a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
16223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers = new HashMap<String, DataRowHandler>();
16233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1624e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, new EmailDataRowHandler());
16253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE,
16263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new CommonDataRowHandler(Im.CONTENT_ITEM_TYPE, Im.TYPE, Im.LABEL));
162767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler(
162867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, StructuredPostal.LABEL));
16293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, new OrganizationDataRowHandler());
16303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, new PhoneDataRowHandler());
163114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new NicknameDataRowHandler());
16323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE,
16333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new StructuredNameRowHandler(mNameSplitter));
1634622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        mDataRowHandlers.put(StructuredPostal.CONTENT_ITEM_TYPE,
1635622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                new StructuredPostalRowHandler(mPostalSplitter));
1636a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        mDataRowHandlers.put(GroupMembership.CONTENT_ITEM_TYPE, new GroupMembershipRowHandler());
1637a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        mDataRowHandlers.put(Photo.CONTENT_ITEM_TYPE, new PhotoDataRowHandler());
16383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
16393d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        if (isLegacyContactImportNeeded()) {
1640568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            importLegacyContactsAsync();
16413d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
1642568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1643c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov        verifyAccounts();
164470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong
16451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        return (db != null);
16464f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
16474f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1648c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov    protected void verifyAccounts() {
1649c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov        AccountManager.get(getContext()).addOnAccountsUpdatedListener(this, null, false);
1650c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov        onAccountsUpdated(AccountManager.get(getContext()).getAccounts());
1651c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov    }
1652c1778ef6fa53b6bf08fd715b3ad70c052c5f1ce9Dmitri Plotnikov
165331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    /* Visible for testing */
1654de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    @Override
165531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    protected OpenHelper getOpenHelper(final Context context) {
165631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov        return OpenHelper.getInstance(context);
165731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    }
165831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
1659285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    /* package */ ContactAggregationScheduler getContactAggregationScheduler() {
1660285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        return mAggregationScheduler;
1661285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
1662285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
1663013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    /* package */ NameSplitter getNameSplitter() {
1664013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov        return mNameSplitter;
1665013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    }
1666013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov
16673d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    protected boolean isLegacyContactImportNeeded() {
16683d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
16693d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        return prefs.getInt(PREF_CONTACTS_IMPORTED, 0) < PREF_CONTACTS_IMPORT_VERSION;
16703d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
16713d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1672568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    protected LegacyContactImporter getLegacyContactImporter() {
1673568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return new LegacyContactImporter(getContext(), this);
1674568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1675568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1676568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /**
1677568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * Imports legacy contacts in a separate thread.  As long as the import process is running
1678568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * all other access to the contacts is blocked.
1679568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     */
1680568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    private void importLegacyContactsAsync() {
1681ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        mAccessLatch = new CountDownLatch(1);
1682568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1683568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        Thread importThread = new Thread("LegacyContactImport") {
1684568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            @Override
1685568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            public void run() {
1686568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                if (importLegacyContacts()) {
1687568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1688568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                    /*
1689568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     * When the import process is done, we can unlock the provider and
1690568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     * start aggregating the imported contacts asynchronously.
1691568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     */
1692ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch.countDown();
1693ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch = null;
1694568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                    scheduleContactAggregation();
1695568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                }
1696568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            }
1697568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        };
1698568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1699568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        importThread.start();
1700568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1701568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
17023d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private boolean importLegacyContacts() {
1703568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        LegacyContactImporter importer = getLegacyContactImporter();
1704568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        if (importLegacyContacts(importer)) {
17053d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
17063d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            Editor editor = prefs.edit();
17073d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            editor.putInt(PREF_CONTACTS_IMPORTED, PREF_CONTACTS_IMPORT_VERSION);
17083d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            editor.commit();
17093d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return true;
17103d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        } else {
17113d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return false;
17123d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
17133d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
17143d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
17153d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /* Visible for testing */
1716568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /* package */ boolean importLegacyContacts(LegacyContactImporter importer) {
17170e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff        boolean aggregatorEnabled = mContactAggregator.isEnabled();
17183d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        mContactAggregator.setEnabled(false);
171973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mImportMode = true;
17203d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        try {
17213d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            importer.importContacts();
17220e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff            mContactAggregator.setEnabled(aggregatorEnabled);
17233d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return true;
17243d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        } catch (Throwable e) {
17253d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov           Log.e(TAG, "Legacy contact import failed", e);
17263d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov           return false;
172773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        } finally {
172873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            mImportMode = false;
17293d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
17303d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
17313d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1732a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    @Override
1733a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    protected void finalize() throws Throwable {
1734a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        if (mContactAggregator != null) {
1735a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov            mContactAggregator.quit();
1736a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        }
1737a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1738a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        super.finalize();
1739a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1740a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1741a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
1742a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Wipes all data from the contacts database.
1743a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
1744a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /* package */ void wipeData() {
1745a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        mOpenHelper.wipeData();
1746a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1747a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1748568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /**
1749568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * While importing and aggregating contacts, this content provider will
1750568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * block all attempts to change contacts data. In particular, it will hold
1751568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * up all contact syncs. As soon as the import process is complete, all
1752568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * processes waiting to write to the provider are unblocked and can proceed
1753568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * to compete for the database transaction monitor.
1754568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     */
1755568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    private void waitForAccess() {
1756ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        CountDownLatch latch = mAccessLatch;
1757ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        if (latch != null) {
1758ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov            while (true) {
1759ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                try {
1760ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    latch.await();
1761ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch = null;
1762ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    return;
1763ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                } catch (InterruptedException e) {
176481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                    Thread.currentThread().interrupt();
1765ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                }
1766ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov            }
1767568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        }
1768568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1769568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1770568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1771568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public Uri insert(Uri uri, ContentValues values) {
1772568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1773568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.insert(uri, values);
1774568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1775568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1776568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1777568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
1778568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1779568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.update(uri, values, selection, selectionArgs);
1780568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1781568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1782568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1783568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public int delete(Uri uri, String selection, String[] selectionArgs) {
1784568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1785568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.delete(uri, selection, selectionArgs);
1786568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1787568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1788568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1789568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
1790568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            throws OperationApplicationException {
1791568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1792568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.applyBatch(operations);
1793568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1794568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
17954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
1796285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    protected void onBeginTransaction() {
1797bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
1798b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "onBeginTransaction");
1799b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
1800285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        super.onBeginTransaction();
18011ea29714ef8fdd62b71f265f27391c22f4a50340Fred Quintana        mContactAggregator.clearPendingAggregations();
1802b5a4add17815167d20a90645779df34cdf45280dFred Quintana        clearTransactionalChanges();
1803b5a4add17815167d20a90645779df34cdf45280dFred Quintana    }
1804b5a4add17815167d20a90645779df34cdf45280dFred Quintana
1805b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private void clearTransactionalChanges() {
1806285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        mInsertedRawContacts.clear();
1807b5a4add17815167d20a90645779df34cdf45280dFred Quintana        mUpdatedRawContacts.clear();
1808df9db5e99572ce9760eb265683134c1f3293928fFred Quintana        mUpdatedSyncStates.clear();
1809285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
1810285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
1811285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    @Override
1812285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    protected void beforeTransactionCommit() {
1813bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
1814b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "beforeTransactionCommit");
1815b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
1816285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        super.beforeTransactionCommit();
1817b5a4add17815167d20a90645779df34cdf45280dFred Quintana        flushTransactionalChanges();
18181ea29714ef8fdd62b71f265f27391c22f4a50340Fred Quintana        mContactAggregator.aggregateInTransaction(mDb);
18191a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (mVisibleTouched) {
18201a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = false;
18211a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mOpenHelper.updateAllVisible();
18221a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        }
1823b5a4add17815167d20a90645779df34cdf45280dFred Quintana    }
1824b5a4add17815167d20a90645779df34cdf45280dFred Quintana
1825b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private void flushTransactionalChanges() {
1826bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
1827b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "flushTransactionChanges");
1828b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
1829b5a4add17815167d20a90645779df34cdf45280dFred Quintana        for (long rawContactId : mInsertedRawContacts) {
1830b5a4add17815167d20a90645779df34cdf45280dFred Quintana            mContactAggregator.insertContact(mDb, rawContactId);
1831285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        }
1832b5a4add17815167d20a90645779df34cdf45280dFred Quintana
1833b5a4add17815167d20a90645779df34cdf45280dFred Quintana        String ids;
1834b5a4add17815167d20a90645779df34cdf45280dFred Quintana        if (!mUpdatedRawContacts.isEmpty()) {
1835b5a4add17815167d20a90645779df34cdf45280dFred Quintana            ids = buildIdsString(mUpdatedRawContacts);
1836b5a4add17815167d20a90645779df34cdf45280dFred Quintana            mDb.execSQL("UPDATE raw_contacts SET version = version + 1 WHERE _id in " + ids,
1837b5a4add17815167d20a90645779df34cdf45280dFred Quintana                    new Object[]{});
1838b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
1839b5a4add17815167d20a90645779df34cdf45280dFred Quintana
1840b5a4add17815167d20a90645779df34cdf45280dFred Quintana        for (Map.Entry<Long, Object> entry : mUpdatedSyncStates.entrySet()) {
1841b5a4add17815167d20a90645779df34cdf45280dFred Quintana            long id = entry.getKey();
1842b5a4add17815167d20a90645779df34cdf45280dFred Quintana            mOpenHelper.getSyncState().update(mDb, id, entry.getValue());
1843b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
1844b5a4add17815167d20a90645779df34cdf45280dFred Quintana
1845b5a4add17815167d20a90645779df34cdf45280dFred Quintana        clearTransactionalChanges();
1846b5a4add17815167d20a90645779df34cdf45280dFred Quintana    }
1847b5a4add17815167d20a90645779df34cdf45280dFred Quintana
1848b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private String buildIdsString(HashSet<Long> ids) {
1849b5a4add17815167d20a90645779df34cdf45280dFred Quintana        StringBuilder idsBuilder = null;
1850b5a4add17815167d20a90645779df34cdf45280dFred Quintana        for (long id : ids) {
1851b5a4add17815167d20a90645779df34cdf45280dFred Quintana            if (idsBuilder == null) {
1852b5a4add17815167d20a90645779df34cdf45280dFred Quintana                idsBuilder = new StringBuilder();
1853b5a4add17815167d20a90645779df34cdf45280dFred Quintana                idsBuilder.append("(");
1854b5a4add17815167d20a90645779df34cdf45280dFred Quintana            } else {
1855b5a4add17815167d20a90645779df34cdf45280dFred Quintana                idsBuilder.append(",");
1856b5a4add17815167d20a90645779df34cdf45280dFred Quintana            }
1857b5a4add17815167d20a90645779df34cdf45280dFred Quintana            idsBuilder.append(id);
1858b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
1859b5a4add17815167d20a90645779df34cdf45280dFred Quintana        idsBuilder.append(")");
1860b5a4add17815167d20a90645779df34cdf45280dFred Quintana        return idsBuilder.toString();
1861285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
1862285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
1863285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    @Override
1864cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    protected void notifyChange() {
186581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        notifyChange(mSyncToNetwork);
186681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        mSyncToNetwork = false;
186781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov    }
186881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov
186981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov    protected void notifyChange(boolean syncToNetwork) {
187081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null,
187181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                syncToNetwork);
1872cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    }
1873568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1874568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    protected void scheduleContactAggregation() {
1875dee54bb86f3608730f0b9f37d8982a7f6b280a85Dmitri Plotnikov        mContactAggregator.schedule();
1876568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1877568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1878285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    private boolean isNewRawContact(long rawContactId) {
1879285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        return mInsertedRawContacts.contains(rawContactId);
1880285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
1881285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
18823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private DataRowHandler getDataRowHandler(final String mimeType) {
18833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        DataRowHandler handler = mDataRowHandlers.get(mimeType);
18843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (handler == null) {
18853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            handler = new CustomDataRowHandler(mimeType);
18863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mDataRowHandlers.put(mimeType, handler);
18873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
18883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        return handler;
18893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
18903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
18914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
1892de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected Uri insertInTransaction(Uri uri, ContentValues values) {
1893bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
1894b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "insertInTransaction: " + uri);
1895b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
1896f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana
1897f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        final boolean callerIsSyncAdapter =
1898f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false);
1899f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana
1900a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
1901a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
190235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1903a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        switch (match) {
190435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
1905de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                id = mOpenHelper.getSyncState().insert(mDb, values);
190635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                break;
190735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1908d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
1909d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                insertContact(values);
19106bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
19116bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
19126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
19135ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
1914f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                final Account account = readAccountFromQueryParams(uri);
1915d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                id = insertRawContact(values, account);
1916f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
1917a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1918a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1919a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
19205ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
19215ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1));
1922f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                id = insertData(values, callerIsSyncAdapter);
1923f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
1924a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1925a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1926a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1927a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case DATA: {
1928f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                id = insertData(values, callerIsSyncAdapter);
1929f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
1930a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1931a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1932a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1933ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
1934ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                final Account account = readAccountFromQueryParams(uri);
19355aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                id = insertGroup(uri, values, account, callerIsSyncAdapter);
1936f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
1937ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
1938ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1939ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1940eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
19415aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                id = insertSettings(uri, values);
194243880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov                mSyncToNetwork |= !callerIsSyncAdapter;
1943eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
1944eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
1945eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
194682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES: {
194782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                id = insertStatusUpdate(values);
19481f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                break;
19491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
19501f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
1951a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            default:
195281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                mSyncToNetwork = true;
1953f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.insert(uri, values);
1954a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
1955a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
19567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        if (id < 0) {
19577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return null;
19587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
19597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
1960de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return ContentUris.withAppendedId(uri, id);
1961a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
1962a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1963a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
1964035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * If account is non-null then store it in the values. If the account is already
1965035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * specified in the values then it must be consistent with the account, if it is non-null.
1966035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @param values the ContentValues to read from and update
1967035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @param account the explicitly provided Account
1968035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @return false if the accounts are inconsistent
19697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
1970035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana    private boolean resolveAccount(ContentValues values, Account account) {
1971035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        // If either is specified then both must be specified.
19726cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
19736cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
1974035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        if (!TextUtils.isEmpty(accountName) || !TextUtils.isEmpty(accountType)) {
1975035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            final Account valuesAccount = new Account(accountName, accountType);
1976035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            if (account != null && !valuesAccount.equals(account)) {
1977035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                return false;
1978035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            }
1979035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            account = valuesAccount;
1980035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
1981035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        if (account != null) {
1982df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana            values.put(RawContacts.ACCOUNT_NAME, account.name);
1983df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana            values.put(RawContacts.ACCOUNT_TYPE, account.type);
1984035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
1985035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        return true;
19867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
19877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
19887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
1989d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov     * Inserts an item in the contacts table
19906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     *
19916bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @param values the values for the new row
19926bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @return the row ID of the newly created row
19936bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     */
1994d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertContact(ContentValues values) {
1995de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        throw new UnsupportedOperationException("Aggregate contacts are created automatically");
19966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    }
19976bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
19986bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    /**
1999a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the contacts table
2000a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
2001a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
2002f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana     * @param account the account this contact should be associated with. may be null.
2003a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
2004a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
2005d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertRawContact(ContentValues values, Account account) {
2006a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        ContentValues overriddenValues = new ContentValues(values);
2007d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        overriddenValues.putNull(RawContacts.CONTACT_ID);
2008f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        if (!resolveAccount(overriddenValues, account)) {
20097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return -1;
20107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
20117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
20123d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        if (values.containsKey(RawContacts.DELETED)
20133d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov                && values.getAsInteger(RawContacts.DELETED) != 0) {
20143d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            overriddenValues.put(RawContacts.AGGREGATION_MODE,
20153d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov                    RawContacts.AGGREGATION_MODE_DISABLED);
20163d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
20173d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
2018023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        long rawContactId =
2019023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov                mDb.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, overriddenValues);
2020023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        mContactAggregator.markNewForAggregation(rawContactId);
2021285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
2022285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        // Trigger creation of a Contact based on this RawContact at the end of transaction
2023285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        mInsertedRawContacts.add(rawContactId);
2024023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        return rawContactId;
2025a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
2026a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2027a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
2028a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the data table
2029a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
2030a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
2031a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
2032a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
2033f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana    private long insertData(ContentValues values, boolean callerIsSyncAdapter) {
2034a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
2035de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.clear();
2036de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.putAll(values);
203767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
2038de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID);
203920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2040de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace package with internal mapping
2041de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String packageName = mValues.getAsString(Data.RES_PACKAGE);
2042de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (packageName != null) {
2043de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
2044de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
2045de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.RES_PACKAGE);
2046508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
2047de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace mimetype with internal mapping
2048de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String mimeType = mValues.getAsString(Data.MIMETYPE);
2049de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (TextUtils.isEmpty(mimeType)) {
2050de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            throw new IllegalArgumentException(Data.MIMETYPE + " is required");
2051de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
20524097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
2053de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.put(DataColumns.MIMETYPE_ID, mOpenHelper.getMimeTypeId(mimeType));
2054de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
2055a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
2056a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        DataRowHandler rowHandler = getDataRowHandler(mimeType);
2057a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        id = rowHandler.insert(mDb, rawContactId, mValues);
2058f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (!callerIsSyncAdapter) {
2059de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            setRawContactDirty(rawContactId);
2060a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
2061b5a4add17815167d20a90645779df34cdf45280dFred Quintana        mUpdatedRawContacts.add(rawContactId);
2062a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
2063a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        if (rowHandler.isAggregationRequired()) {
2064a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            triggerAggregation(rawContactId);
2065a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
2066a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        return id;
20674f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
20684f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
20698e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov    private void triggerAggregation(long rawContactId) {
20708e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        if (!mContactAggregator.isEnabled()) {
20718e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            return;
20728e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        }
20738e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
20748e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        int aggregationMode = mOpenHelper.getAggregationMode(rawContactId);
2075f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        switch (aggregationMode) {
20768e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DISABLED:
20778e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                break;
20788e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
20798e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DEFAULT: {
2080421782cb554e5050cf62a86b98df6520038dcd15Dmitri Plotnikov                mContactAggregator.markForAggregation(rawContactId);
2081f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
20828e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
20838e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
20848e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_SUSPENDED: {
20858e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                long contactId = mOpenHelper.getContactId(rawContactId);
2086f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
20878e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                if (contactId != 0) {
20888e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                    mContactAggregator.updateAggregateData(contactId);
20898e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                }
2090f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
20918e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
2092f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
2093c100221f706afc08409e8317a27d6850b11c54d3Omari Stephens            case RawContacts.AGGREGATION_MODE_IMMEDIATE: {
20948e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                long contactId = mOpenHelper.getContactId(rawContactId);
20958e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                mContactAggregator.aggregateContact(mDb, rawContactId, contactId);
2096f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
20978e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
2098f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        }
2099f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
2100f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
2101a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
21025ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * Returns the group id of the group with sourceId and the same account as rawContactId.
21039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * If the group doesn't already exist then it is first created,
21049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param db SQLiteDatabase to use for this operation
21055ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * @param rawContactId the contact this group is associated with
21069261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param sourceId the sourceIf of the group to query or create
21079261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @return the group id of the existing or created group
21089261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalArgumentException if the contact is not associated with an account
21099261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalStateException if a group needs to be created but the creation failed
21109261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     */
21115ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private long getOrMakeGroup(SQLiteDatabase db, long rawContactId, String sourceId) {
21129261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        Account account = null;
21136cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Cursor c = db.query(ContactsQuery.TABLE, ContactsQuery.PROJECTION, RawContacts._ID + "="
21145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                + rawContactId, null, null, null, null);
21159261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
21169261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            if (c.moveToNext()) {
211767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                final String accountName = c.getString(ContactsQuery.ACCOUNT_NAME);
211867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                final String accountType = c.getString(ContactsQuery.ACCOUNT_TYPE);
21199261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
21209261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    account = new Account(accountName, accountType);
21219261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
21229261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
21239261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
21249261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
21259261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
21269261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        if (account == null) {
21279261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            throw new IllegalArgumentException("if the groupmembership only "
21289261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "has a sourceid the the contact must be associate with "
21299261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "an account");
21309261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
21319261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
21329261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // look up the group that contains this sourceId and has the same account name and type
21335ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        // as the contact refered to by rawContactId
21346cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        c = db.query(Tables.GROUPS, new String[]{RawContacts._ID},
21359261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Clauses.GROUP_HAS_ACCOUNT_AND_SOURCE_ID,
2136df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                new String[]{sourceId, account.name, account.type}, null, null, null);
21379261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
21389261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            if (c.moveToNext()) {
21399261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                return c.getLong(0);
21409261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            } else {
21419261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                ContentValues groupValues = new ContentValues();
2142df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                groupValues.put(Groups.ACCOUNT_NAME, account.name);
2143df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                groupValues.put(Groups.ACCOUNT_TYPE, account.type);
21449261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                groupValues.put(Groups.SOURCE_ID, sourceId);
21459261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                long groupId = db.insert(Tables.GROUPS, Groups.ACCOUNT_NAME, groupValues);
21469261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (groupId < 0) {
21479261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    throw new IllegalStateException("unable to create a new group with "
21489261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            + "this sourceid: " + groupValues);
21499261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
21509261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                return groupId;
21519261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
21529261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
21539261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
21549261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
21559261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    }
21569261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
21579261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /**
215820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     * Delete data row by row so that fixing of primaries etc work correctly.
215920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     */
2160f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana    private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) {
216120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int count = 0;
216220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2163de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
2164de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
216514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, selection, selectionArgs, null);
2166de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        try {
2167de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            while(c.moveToNext()) {
216814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
216914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
2170a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                DataRowHandler rowHandler = getDataRowHandler(mimeType);
2171a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                count += rowHandler.delete(mDb, c);
2172f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                if (!callerIsSyncAdapter) {
217388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                    setRawContactDirty(rawContactId);
2174a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                    if (rowHandler.isAggregationRequired()) {
2175a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                        triggerAggregation(rawContactId);
2176a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                    }
217788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                }
217820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
217920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
2180de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            c.close();
218120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
218220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
218320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        return count;
218420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
218520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
218688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov    /**
218788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     * Delete a data row provided that it is one of the allowed mime types.
218888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     */
218920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    public int deleteData(long dataId, String[] allowedMimeTypes) {
2190f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
219188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
219288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
219314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, Data._ID + "=" + dataId, null,
219414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                null);
2195f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
219620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        try {
219720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!c.moveToFirst()) {
219820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                return 0;
219920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
220020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
220114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
220220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            boolean valid = false;
220320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            for (int i = 0; i < allowedMimeTypes.length; i++) {
220420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                if (TextUtils.equals(mimeType, allowedMimeTypes[i])) {
220520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    valid = true;
220620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    break;
220720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                }
220820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
220920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
221020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!valid) {
22117a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException("Data type mismatch: expected "
221220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                        + Lists.newArrayList(allowedMimeTypes));
221320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
221420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2215a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            DataRowHandler rowHandler = getDataRowHandler(mimeType);
2216a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            int count = rowHandler.delete(mDb, c);
22178e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
2218a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            if (rowHandler.isAggregationRequired()) {
2219a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                triggerAggregation(rawContactId);
2220a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            }
22218e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            return count;
222220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
222320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            c.close();
222420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
222520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
222620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
222720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    /**
2228ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Inserts an item in the groups table
2229ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
22305aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private long insertGroup(Uri uri, ContentValues values, Account account, boolean callerIsSyncAdapter) {
2231ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        ContentValues overriddenValues = new ContentValues(values);
2232ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        if (!resolveAccount(overriddenValues, account)) {
2233ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            return -1;
2234ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        }
2235ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2236ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Replace package with internal mapping
223767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        final String packageName = overriddenValues.getAsString(Groups.RES_PACKAGE);
223867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        if (packageName != null) {
223967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            overriddenValues.put(GroupsColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
224067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        }
224167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        overriddenValues.remove(Groups.RES_PACKAGE);
2242ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2243f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (!callerIsSyncAdapter) {
224473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            overriddenValues.put(Groups.DIRTY, 1);
224573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
224673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
2247ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        long result = mDb.insert(Tables.GROUPS, Groups.TITLE, overriddenValues);
2248ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey
22491a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (overriddenValues.containsKey(Groups.GROUP_VISIBLE)) {
22501a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
2251ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        }
2252ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey
2253ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        return result;
2254ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
2255ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
22565aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private long insertSettings(Uri uri, ContentValues values) {
2257e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final long id = mDb.insert(Tables.SETTINGS, null, values);
22585aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey
22591a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (values.containsKey(Settings.UNGROUPED_VISIBLE)) {
22601a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
2261e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
22621a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey
2263e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return id;
2264e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
2265e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
2266ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
226782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov     * Inserts a status update.
22681f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     */
226982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    public long insertStatusUpdate(ContentValues values) {
227082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        final String handle = values.getAsString(StatusUpdates.IM_HANDLE);
227182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        if (TextUtils.isEmpty(handle) || !values.containsKey(StatusUpdates.PROTOCOL)) {
22724dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required");
22734dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        }
22744dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov
227582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        final long protocol = values.getAsLong(StatusUpdates.PROTOCOL);
22764dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        String customProtocol = null;
22774dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov
22784dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        if (protocol == Im.PROTOCOL_CUSTOM) {
227982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL);
22804dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            if (TextUtils.isEmpty(customProtocol)) {
22814dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                throw new IllegalArgumentException(
22824dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                        "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM");
22834dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            }
22841f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
22851f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2286dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton        long rawContactId = -1;
2287dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton        long contactId = -1;
228882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        Long dataId = values.getAsLong(StatusUpdates.DATA_ID);
228970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        StringBuilder selection = new StringBuilder();
22901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String[] selectionArgs;
2291dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton
2292dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton        if (dataId != null) {
2293dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            // Lookup the contact info for the given data row.
2294dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton
2295dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            selection.append(Tables.DATA + "." + Data._ID + "=");
2296dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            selection.append(dataId);
2297dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            selectionArgs = null;
22981f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } else {
2299dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            // Lookup the data row to attach this presence update to
2300dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton
2301dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            // TODO: generalize to allow other providers to match against email
2302dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol;
2303dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton
2304dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            if (matchEmail) {
2305dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                selection.append(
2306dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                        "((" + MimetypesColumns.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'"
2307dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                        + " AND " + Im.PROTOCOL + "=?"
2308dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                        + " AND " + Im.DATA + "=?");
2309dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                if (customProtocol != null) {
2310dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                    selection.append(" AND " + Im.CUSTOM_PROTOCOL + "=");
2311dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                    DatabaseUtils.appendEscapedSQLString(selection, customProtocol);
2312dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                }
2313dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                selection.append(") OR ("
2314dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                        + MimetypesColumns.MIMETYPE + "='" + Email.CONTENT_ITEM_TYPE + "'"
2315dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                        + " AND " + Email.DATA + "=?"
2316dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                        + "))");
2317dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                selectionArgs = new String[] { String.valueOf(protocol), handle, handle };
2318dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            } else {
2319dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                selection.append(
2320dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                        MimetypesColumns.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'"
2321dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                        + " AND " + Im.PROTOCOL + "=?"
2322dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                        + " AND " + Im.DATA + "=?");
2323dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                if (customProtocol != null) {
2324dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                    selection.append(" AND " + Im.CUSTOM_PROTOCOL + "=");
2325dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                    DatabaseUtils.appendEscapedSQLString(selection, customProtocol);
2326dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                }
23274dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov
2328dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                selectionArgs = new String[] { String.valueOf(protocol), handle };
2329dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            }
23301f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
233182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            if (values.containsKey(StatusUpdates.DATA_ID)) {
2332dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                selection.append(" AND " + DataColumns.CONCRETE_ID + "=")
233382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                        .append(values.getAsLong(StatusUpdates.DATA_ID));
2334dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            }
233570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
233600ec508630251d6c6e3746469c9428f5a8cd5996Jeff Sharkey        selection.append(" AND ").append(getContactsRestrictions());
233770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
23381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        Cursor cursor = null;
23391f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        try {
2340de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION,
234170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                    selection.toString(), selectionArgs, null, null, null);
23421f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            if (cursor.moveToFirst()) {
234367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                dataId = cursor.getLong(DataContactsQuery.DATA_ID);
23445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID);
2345e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                contactId = cursor.getLong(DataContactsQuery.CONTACT_ID);
23461f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            } else {
23471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                // No contact found, return a null URI
23481f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                return -1;
23491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
23501f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } finally {
235131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            if (cursor != null) {
235231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                cursor.close();
235331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
23541f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
23551f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
235682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        if (values.containsKey(StatusUpdates.PRESENCE)) {
2357a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            if (customProtocol == null) {
2358a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                // We cannot allow a null in the custom protocol field, because SQLite3 does not
2359a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                // properly enforce uniqueness of null values
2360a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                customProtocol = "";
2361a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            }
2362a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
2363a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mValues.clear();
236482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.DATA_ID, dataId);
2365a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId);
2366a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mValues.put(PresenceColumns.CONTACT_ID, contactId);
236782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.PROTOCOL, protocol);
236882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol);
236982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.IM_HANDLE, handle);
237082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            if (values.containsKey(StatusUpdates.IM_ACCOUNT)) {
237182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT));
2372a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            }
237382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.PRESENCE,
237482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                    values.getAsString(StatusUpdates.PRESENCE));
23751f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2376a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            // Insert the presence update
2377a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mDb.replace(Tables.PRESENCE, null, mValues);
2378a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        }
2379e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
238082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        if (values.containsKey(StatusUpdates.STATUS)) {
238182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            String status = values.getAsString(StatusUpdates.STATUS);
2382a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            if (TextUtils.isEmpty(status)) {
2383a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                mStatusUpdateDelete.bindLong(1, dataId);
2384a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                mStatusUpdateDelete.execute();
238582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            } else if (values.containsKey(StatusUpdates.STATUS_TIMESTAMP)) {
238682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP);
2387a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                mStatusUpdateReplace.bindLong(1, dataId);
2388a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                mStatusUpdateReplace.bindLong(2, timestamp);
2389a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                mStatusUpdateReplace.bindString(3, status);
2390a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                mStatusUpdateReplace.execute();
2391a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            } else {
2392a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                long timestamp = System.currentTimeMillis();
2393a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
2394a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                try {
2395a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateInsert.bindLong(1, dataId);
2396a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateInsert.bindLong(2, timestamp);
2397a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateInsert.bindString(3, status);
2398a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateInsert.executeInsert();
2399a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                } catch (SQLiteConstraintException e) {
2400a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    // The row already exists - update it
2401a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateAutoTimestamp.bindLong(1, timestamp);
2402a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateAutoTimestamp.bindString(2, status);
2403a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateAutoTimestamp.bindLong(3, dataId);
2404a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateAutoTimestamp.bindString(4, status);
2405a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    mStatusUpdateAutoTimestamp.execute();
2406a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                }
2407e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            }
2408e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        }
2409bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov
2410a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        if (contactId != -1) {
2411a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mLastStatusUpdate.bindLong(1, contactId);
2412a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mLastStatusUpdate.bindLong(2, contactId);
2413a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mLastStatusUpdate.execute();
2414a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        }
2415a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
2416a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        return dataId;
24171f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    }
24181f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
24194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
2420de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
2421bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
2422b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "deleteInTransaction: " + uri);
2423b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2424b5a4add17815167d20a90645779df34cdf45280dFred Quintana        flushTransactionalChanges();
2425f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        final boolean callerIsSyncAdapter =
2426f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false);
2427508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        final int match = sUriMatcher.match(uri);
2428508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        switch (match) {
242935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
2430de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mOpenHelper.getSyncState().delete(mDb, selection, selectionArgs);
243135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2432b5a4add17815167d20a90645779df34cdf45280dFred Quintana            case SYNCSTATE_ID:
2433b5a4add17815167d20a90645779df34cdf45280dFred Quintana                String selectionWithId =
2434b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ")
2435b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        + (selection == null ? "" : " AND (" + selection + ")");
2436b5a4add17815167d20a90645779df34cdf45280dFred Quintana                return mOpenHelper.getSyncState().delete(mDb, selectionWithId, selectionArgs);
2437b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2438cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            case CONTACTS: {
2439cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                // TODO
2440cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                return 0;
2441cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            }
2442cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
2443d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
2444d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
2445cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                return deleteContact(contactId);
24466bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
24476bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
24482e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            case CONTACTS_LOOKUP:
24492e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            case CONTACTS_LOOKUP_ID: {
24502e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final List<String> pathSegments = uri.getPathSegments();
24512e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final int segmentCount = pathSegments.size();
24522e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                if (segmentCount < 3) {
24532e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                    throw new IllegalArgumentException("URI " + uri + " is missing a lookup key");
24542e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                }
24552e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final String lookupKey = pathSegments.get(2);
24562e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final long contactId = lookupContactIdByLookupKey(mDb, lookupKey);
24572e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                return deleteContact(contactId);
24582e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            }
24592e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey
24602971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            case RAW_CONTACTS: {
24612971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                int numDeletes = 0;
24622971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                Cursor c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID},
2463e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs, null, null, null);
24642971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                try {
24652971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    while (c.moveToNext()) {
24662971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        final long rawContactId = c.getLong(0);
2467f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                        numDeletes += deleteRawContact(rawContactId, callerIsSyncAdapter);
24682971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    }
24692971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                } finally {
24702971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    c.close();
24712971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                }
24722971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return numDeletes;
24732971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            }
24742971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana
24755ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
24762971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                final long rawContactId = ContentUris.parseId(uri);
2477f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                return deleteRawContact(rawContactId, callerIsSyncAdapter);
2478508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
2479508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
248020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
2481f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
2482944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                return deleteData(appendAccountToSelection(uri, selection), selectionArgs,
2483f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                        callerIsSyncAdapter);
248420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
248520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
248648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case DATA_ID:
248748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID:
248848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID:
248948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID: {
2490508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey                long dataId = ContentUris.parseId(uri);
2491f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
2492f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                return deleteData(Data._ID + "=" + dataId, null, callerIsSyncAdapter);
2493ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2494ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2495ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
2496f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
24975aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter);
24982971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            }
24992971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana
25002971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            case GROUPS: {
25012971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                int numDeletes = 0;
25022971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups._ID},
2503e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs, null, null, null);
25042971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                try {
25052971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    while (c.moveToNext()) {
25065aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                        numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter);
25072971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    }
25082971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                } finally {
25092971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    c.close();
25102971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                }
251181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (numDeletes > 0) {
2512f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
251381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
25142971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return numDeletes;
2515508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
2516508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
2517eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
251843880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov                mSyncToNetwork |= !callerIsSyncAdapter;
25195aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                return deleteSettings(uri, selection, selectionArgs);
2520eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
2521eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
252282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES: {
2523eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                return mDb.delete(Tables.PRESENCE, selection, selectionArgs);
25241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
25251f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
252681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            default: {
252781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                mSyncToNetwork = true;
25283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                return mLegacyApiSupport.delete(uri, selection, selectionArgs);
252981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            }
2530508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        }
25314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
25324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
25332971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana    private boolean readBooleanQueryParameter(Uri uri, String name, boolean defaultValue) {
25342971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana        final String flag = uri.getQueryParameter(name);
25352971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana        return flag == null
25362971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                ? defaultValue
25372971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                : (!"false".equals(flag.toLowerCase()) && !"0".equals(flag.toLowerCase()));
253894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
253994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
25405aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) {
254194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        final long groupMembershipMimetypeId = mOpenHelper
254294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
2543de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mDb.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "="
254494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "="
254594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupId, null);
254694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
254794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        try {
2548f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            if (callerIsSyncAdapter) {
2549de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null);
255094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            } else {
255194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.clear();
255294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.put(Groups.DELETED, 1);
2553f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mValues.put(Groups.DIRTY, 1);
2554de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, null);
255594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            }
255694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        } finally {
25571a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
255894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
255994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
256094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
25615aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private int deleteSettings(Uri uri, String selection, String[] selectionArgs) {
2562e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final int count = mDb.delete(Tables.SETTINGS, selection, selectionArgs);
25631a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        mVisibleTouched = true;
2564e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return count;
2565e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
2566e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
2567cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov    private int deleteContact(long contactId) {
2568cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        Cursor c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID},
2569cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                RawContacts.CONTACT_ID + "=" + contactId, null, null, null, null);
2570cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        try {
2571cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            while (c.moveToNext()) {
2572cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                long rawContactId = c.getLong(0);
2573cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                markRawContactAsDeleted(rawContactId);
2574cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            }
2575cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        } finally {
2576cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            c.close();
2577cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        }
2578cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
2579cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        return mDb.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null);
2580cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov    }
2581cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
2582f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana    public int deleteRawContact(long rawContactId, boolean callerIsSyncAdapter) {
2583f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (callerIsSyncAdapter) {
258414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mDb.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null);
2585de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            return mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null);
258633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        } else {
2587a5bfaf55790262eea97de432d9e7f313c219c066Dmitri Plotnikov            mOpenHelper.removeContactIfSingleton(rawContactId);
2588cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            return markRawContactAsDeleted(rawContactId);
258933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        }
259033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
259133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
2592cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov    private int markRawContactAsDeleted(long rawContactId) {
259381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        mSyncToNetwork = true;
259481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov
2595cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.clear();
2596cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContacts.DELETED, 1);
2597cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
2598cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1);
2599cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.putNull(RawContacts.CONTACT_ID);
2600cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContacts.DIRTY, 1);
2601cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        return updateRawContact(rawContactId, mValues);
2602cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov    }
2603cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
26044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
2605de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int updateInTransaction(Uri uri, ContentValues values, String selection,
2606de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            String[] selectionArgs) {
2607bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
2608b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "updateInTransaction: " + uri);
2609b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2610b5a4add17815167d20a90645779df34cdf45280dFred Quintana
261135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        int count = 0;
261200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
261300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        final int match = sUriMatcher.match(uri);
2614b5a4add17815167d20a90645779df34cdf45280dFred Quintana        if (match == SYNCSTATE_ID && selection == null) {
2615b5a4add17815167d20a90645779df34cdf45280dFred Quintana            long rowId = ContentUris.parseId(uri);
2616b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Object data = values.get(ContactsContract.SyncStateColumns.DATA);
2617b5a4add17815167d20a90645779df34cdf45280dFred Quintana            mUpdatedSyncStates.put(rowId, data);
2618b5a4add17815167d20a90645779df34cdf45280dFred Quintana            return 1;
2619b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2620b5a4add17815167d20a90645779df34cdf45280dFred Quintana        flushTransactionalChanges();
2621f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        final boolean callerIsSyncAdapter =
2622f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false);
262300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        switch(match) {
262435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
2625b5a4add17815167d20a90645779df34cdf45280dFred Quintana                return mOpenHelper.getSyncState().update(mDb, values,
2626b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        appendAccountToSelection(uri, selection), selectionArgs);
2627b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2628b5a4add17815167d20a90645779df34cdf45280dFred Quintana            case SYNCSTATE_ID: {
2629b5a4add17815167d20a90645779df34cdf45280dFred Quintana                selection = appendAccountToSelection(uri, selection);
2630b5a4add17815167d20a90645779df34cdf45280dFred Quintana                String selectionWithId =
2631b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ")
2632b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        + (selection == null ? "" : " AND (" + selection + ")");
2633b5a4add17815167d20a90645779df34cdf45280dFred Quintana                return mOpenHelper.getSyncState().update(mDb, values,
2634b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        selectionWithId, selectionArgs);
2635b5a4add17815167d20a90645779df34cdf45280dFred Quintana            }
263635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2637d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
26388c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                count = updateContactOptions(values, selection, selectionArgs);
263900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
264000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
264100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
2642d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
26438c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                count = updateContactOptions(ContentUris.parseId(uri), values);
2644c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                break;
2645c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar            }
2646c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
26472e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            case CONTACTS_LOOKUP:
26482e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            case CONTACTS_LOOKUP_ID: {
26492e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final List<String> pathSegments = uri.getPathSegments();
26502e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final int segmentCount = pathSegments.size();
26512e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                if (segmentCount < 3) {
26522e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                    throw new IllegalArgumentException("URI " + uri + " is missing a lookup key");
26532e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                }
26542e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final String lookupKey = pathSegments.get(2);
26552e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final long contactId = lookupContactIdByLookupKey(mDb, lookupKey);
26568c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                count = updateContactOptions(contactId, values);
26572e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                break;
26582e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            }
26592e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey
26607d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh            case RAW_CONTACTS_DATA: {
26617d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                final String rawContactId = uri.getPathSegments().get(1);
26627d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ")
26637d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                    + (selection == null ? "" : " AND " + selection);
26647d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh
26657d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter);
26667d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh
26677d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                break;
26687d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh            }
26697d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh
267020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
2671944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                count = updateData(uri, values, appendAccountToSelection(uri, selection),
2672f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                        selectionArgs, callerIsSyncAdapter);
267381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
2674f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
267581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
267620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                break;
267720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
2678c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
267948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case DATA_ID:
268048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID:
268148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID:
268248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID: {
2683f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter);
268481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
2685f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
268681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
268700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
268800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
26897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
26905ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
26915ac5c70d1165309302ebcc931f51723e37d31e0bJeff Sharkey                selection = appendAccountToSelection(uri, selection);
26924529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                count = updateRawContacts(values, selection, selectionArgs);
26937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
26947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
26957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
26965ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
269733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
26984529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                if (selection != null) {
26994529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                    count = updateRawContacts(values, RawContacts._ID + "=" + rawContactId
27004529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                                    + " AND(" + selection + ")", selectionArgs);
27014529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                } else {
27024529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                    count = updateRawContact(rawContactId, values);
27034529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                }
27047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
27057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
27067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
2707ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
27085aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                count = updateGroups(uri, values, appendAccountToSelection(uri, selection),
2709f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                        selectionArgs, callerIsSyncAdapter);
271081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
2711f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
271281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
2713ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2714ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2715ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2716ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
2717ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
271873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                String selectionWithId = (Groups._ID + "=" + groupId + " ")
271973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        + (selection == null ? "" : " AND " + selection);
27205aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                count = updateGroups(uri, values, selectionWithId, selectionArgs,
27215aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                        callerIsSyncAdapter);
272281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
2723f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
272481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
2725ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2726ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2727ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2728127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
2729de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateAggregationException(mDb, values);
2730b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
2731b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
2732b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
2733eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
27345aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                count = updateSettings(uri, values, selection, selectionArgs);
273543880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov                mSyncToNetwork |= !callerIsSyncAdapter;
2736eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
2737eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
2738eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
273981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            default: {
274081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                mSyncToNetwork = true;
2741f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.update(uri, values, selection, selectionArgs);
274281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            }
274300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        }
274400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
274500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        return count;
27464f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
27474f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
27485aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private int updateGroups(Uri uri, ContentValues values, String selectionWithId,
2749f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            String[] selectionArgs, boolean callerIsSyncAdapter) {
275073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
275173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        ContentValues updatedValues;
2752f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (!callerIsSyncAdapter && !values.containsKey(Groups.DIRTY)) {
275373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = mValues;
275473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.clear();
275573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.putAll(values);
275673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.put(Groups.DIRTY, 1);
275773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        } else {
275873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = values;
275973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
276073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
2761ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        int count = mDb.update(Tables.GROUPS, updatedValues, selectionWithId, selectionArgs);
27621a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) {
27631a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
276494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
276594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        return count;
276694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
276794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
27685aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private int updateSettings(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
2769e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final int count = mDb.update(Tables.SETTINGS, values, selection, selectionArgs);
27701a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (values.containsKey(Settings.UNGROUPED_VISIBLE)) {
27711a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
2772e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
2773e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return count;
2774e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
2775e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
27764529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov    private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs) {
27774529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        if (values.containsKey(RawContacts.CONTACT_ID)) {
27784529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " +
27794529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                    "in content values. Contact IDs are assigned automatically");
27804529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        }
278173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
27824529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        int count = 0;
27834529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        Cursor cursor = mDb.query(mOpenHelper.getRawContactView(),
278451bf5ea9531b9da72caff607dbdf35fd6f61cbe2Jeff Sharkey                new String[] { RawContacts._ID }, selection,
27854529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                selectionArgs, null, null, null);
27864529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        try {
27874529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            while (cursor.moveToNext()) {
27884529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                long rawContactId = cursor.getLong(0);
27894529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                updateRawContact(rawContactId, values);
27904529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                count++;
27914529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            }
27924529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        } finally {
27934529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            cursor.close();
27944529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        }
27954529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov
27964529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        return count;
27974529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov    }
27984529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov
27994529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov    private int updateRawContact(long rawContactId, ContentValues values) {
280019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        final String selection = RawContacts._ID + " = " + rawContactId;
280119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED)
280219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                && values.getAsInteger(RawContacts.DELETED) == 0);
280319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        int previousDeleted = 0;
280419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        if (requestUndoDelete) {
280519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            Cursor cursor = mDb.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, selection,
280619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                    null, null, null, null);
280719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            try {
280819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                if (cursor.moveToFirst()) {
280919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                    previousDeleted = cursor.getInt(RawContactsQuery.DELETED);
281019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                }
281119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            } finally {
281219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                cursor.close();
281319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            }
281419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            values.put(ContactsContract.RawContacts.AGGREGATION_MODE,
281519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                    ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT);
281619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        }
281719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        int count = mDb.update(Tables.RAW_CONTACTS, values, selection, null);
28185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (count != 0) {
2819433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey            if (values.containsKey(RawContacts.STARRED)) {
28204529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                mContactAggregator.updateStarred(rawContactId);
2821433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey            }
2822285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            if (values.containsKey(RawContacts.SOURCE_ID)) {
2823285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateLookupKey(mDb, rawContactId);
2824285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
282519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            if (requestUndoDelete && previousDeleted == 1) {
282619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                // undo delete, needs aggregation again.
282719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                mInsertedRawContacts.add(rawContactId);
282819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            }
28295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
28305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return count;
283133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
283233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
2833321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    private int updateData(Uri uri, ContentValues values, String selection,
2834f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            String[] selectionArgs, boolean callerIsSyncAdapter) {
283520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.clear();
283620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.putAll(values);
283720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data._ID);
28385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mValues.remove(Data.RAW_CONTACT_ID);
283920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
284020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
284120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        String packageName = values.getAsString(Data.RES_PACKAGE);
284220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        if (packageName != null) {
284320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.remove(Data.RES_PACKAGE);
284420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
284520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
284620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
284770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsSuperPrimary = mValues.containsKey(Data.IS_SUPER_PRIMARY);
284870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsPrimary = mValues.containsKey(Data.IS_PRIMARY);
284920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
285020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // Remove primary or super primary values being set to 0. This is disallowed by the
285120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // content provider.
285270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsSuperPrimary && mValues.getAsInteger(Data.IS_SUPER_PRIMARY) == 0) {
285320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsSuperPrimary = false;
285470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_SUPER_PRIMARY);
285520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
285670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsPrimary && mValues.getAsInteger(Data.IS_PRIMARY) == 0) {
285720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsPrimary = false;
285870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_PRIMARY);
285920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
286020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2861653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        int count = 0;
286220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2863653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
2864653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        // so we don't need to worry about updating data we don't have permission to read.
286514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(uri, DataUpdateQuery.COLUMNS, selection, selectionArgs, null);
2866653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        try {
2867653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            while(c.moveToNext()) {
2868f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                count += updateData(mValues, c, callerIsSyncAdapter);
286920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
2870653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        } finally {
2871653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            c.close();
287220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
287320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2874653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        return count;
287520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
287620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2877f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana    private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) {
2878653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        if (values.size() == 0) {
2879653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return 0;
2880321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        }
2881653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
288214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        final String mimeType = c.getString(DataUpdateQuery.MIMETYPE);
2883a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        DataRowHandler rowHandler = getDataRowHandler(mimeType);
2884f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        rowHandler.update(mDb, values, c, callerIsSyncAdapter);
28858e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
2886a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        if (rowHandler.isAggregationRequired()) {
2887a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            triggerAggregation(rawContactId);
2888a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
28898e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
2890653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        return 1;
2891321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    }
2892321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana
28938c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov    private int updateContactOptions(ContentValues values, String selection,
28948c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            String[] selectionArgs) {
28958c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        int count = 0;
28968c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        Cursor cursor = mDb.query(mOpenHelper.getContactView(),
28978c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                new String[] { Contacts._ID }, selection,
28988c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                selectionArgs, null, null, null);
28998c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        try {
29008c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            while (cursor.moveToNext()) {
29018c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                long contactId = cursor.getLong(0);
29028c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                updateContactOptions(contactId, values);
29038c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                count++;
29048c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            }
29058c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        } finally {
29068c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            cursor.close();
29078c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        }
29088c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
29098c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        return count;
29108c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov    }
29118c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
29128c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov    private int updateContactOptions(long contactId, ContentValues values) {
2913d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
29148c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        mValues.clear();
29158c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        OpenHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE,
2916d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.CUSTOM_RINGTONE);
29178c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        OpenHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL,
2918d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.SEND_TO_VOICEMAIL);
29198c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        OpenHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED,
2920d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.LAST_TIME_CONTACTED);
29218c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        OpenHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED,
2922d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.TIMES_CONTACTED);
29238c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        OpenHelper.copyLongValue(mValues, RawContacts.STARRED,
2924d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.STARRED);
2925d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
2926d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // Nothing to update - just return
29278c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        if (mValues.size() == 0) {
2928d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov            return 0;
2929d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        }
2930d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
29318c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        if (mValues.containsKey(RawContacts.STARRED)) {
2932c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey            // Mark dirty when changing starred to trigger sync
29338c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            mValues.put(RawContacts.DIRTY, 1);
2934c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey        }
2935c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey
29368c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        mDb.update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=" + contactId, null);
29378c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
29388c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        // Copy changeable values to prevent automatically managed fields from
29398c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        // being explicitly updated by clients.
29408c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        mValues.clear();
29418c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        OpenHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE,
29428c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.CUSTOM_RINGTONE);
29438c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        OpenHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL,
29448c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.SEND_TO_VOICEMAIL);
29458c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        OpenHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED,
29468c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.LAST_TIME_CONTACTED);
29478c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        OpenHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED,
29488c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.TIMES_CONTACTED);
29498c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        OpenHelper.copyLongValue(mValues, RawContacts.STARRED,
29508c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.STARRED);
29518c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
29528c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        return mDb.update(Tables.CONTACTS, mValues, Contacts._ID + "=" + contactId, null);
2953f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
2954d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
2955d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    public void updateContactTime(long contactId, long lastTimeContacted) {
2956f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        mLastTimeContactedUpdate.bindLong(1, lastTimeContacted);
2957d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        mLastTimeContactedUpdate.bindLong(2, contactId);
2958f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        mLastTimeContactedUpdate.execute();
2959d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov    }
2960d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
2961127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov    private int updateAggregationException(SQLiteDatabase db, ContentValues values) {
2962127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        int exceptionType = values.getAsInteger(AggregationExceptions.TYPE);
29630c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1);
29640c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2);
296580c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
29660c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        long rawContactId1, rawContactId2;
29670c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        if (rcId1 < rcId2) {
29680c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId1 = rcId1;
29690c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId2 = rcId2;
29700c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        } else {
29710c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId2 = rcId1;
29720c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId1 = rcId2;
2973b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        }
2974127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
29750c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) {
29760c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            db.delete(Tables.AGGREGATION_EXCEPTIONS,
29770c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov                    AggregationExceptions.RAW_CONTACT_ID1 + "=" + rawContactId1 + " AND "
29780c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov                    + AggregationExceptions.RAW_CONTACT_ID2 + "=" + rawContactId2, null);
29790c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        } else {
29806bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov            ContentValues exceptionValues = new ContentValues(3);
29816bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov            exceptionValues.put(AggregationExceptions.TYPE, exceptionType);
29820c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
29830c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
29840c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID,
29850c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov                    exceptionValues);
2986127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        }
2987127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
2988dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov        mContactAggregator.markForAggregation(rawContactId1);
2989dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov        mContactAggregator.markForAggregation(rawContactId2);
2990dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov
29910c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        long contactId1 = mOpenHelper.getContactId(rawContactId1);
29920c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        mContactAggregator.aggregateContact(db, rawContactId1, contactId1);
29930c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov
29940c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        long contactId2 = mOpenHelper.getContactId(rawContactId2);
29950c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        mContactAggregator.aggregateContact(db, rawContactId2, contactId2);
2996127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
2997127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // The return value is fake - we just confirm that we made a change, not count actual
2998127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // rows changed.
2999127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        return 1;
3000b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    }
3001b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
300270d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong    public void onAccountsUpdated(Account[] accounts) {
300370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        mDb = mOpenHelper.getWritableDatabase();
300470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        if (mDb == null) return;
300570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong
300670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        Set<Account> validAccounts = Sets.newHashSet();
300770d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        for (Account account : accounts) {
300870d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            validAccounts.add(new Account(account.name, account.type));
300970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        }
301070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        ArrayList<Account> accountsToDelete = new ArrayList<Account>();
301170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong
301270d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        mDb.beginTransaction();
301370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        try {
301448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
30155f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana            for (String table : new String[]{Tables.RAW_CONTACTS, Tables.GROUPS, Tables.SETTINGS}) {
30165f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                // Find all the accounts the contacts DB knows about, mark the ones that aren't
30175f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                // in the valid set for deletion.
30185f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                Cursor c = mDb.rawQuery("SELECT DISTINCT account_name, account_type from "
30195f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                        + table, null);
30205f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                while (c.moveToNext()) {
30215f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                    if (c.getString(0) != null && c.getString(1) != null) {
30225f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                        Account currAccount = new Account(c.getString(0), c.getString(1));
30235f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                        if (!validAccounts.contains(currAccount)) {
30245f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                            accountsToDelete.add(currAccount);
30255f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                        }
302670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong                    }
302770d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong                }
30285f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                c.close();
302970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            }
303070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong
303170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            for (Account account : accountsToDelete) {
30325f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                Log.d(TAG, "removing data for removed account " + account);
303370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong                String[] params = new String[]{account.name, account.type};
303470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong                mDb.execSQL("DELETE FROM " + Tables.GROUPS
303570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong                        + " WHERE account_name = ? AND account_type = ?", params);
303670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong                mDb.execSQL("DELETE FROM " + Tables.PRESENCE
303770d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong                        + " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (SELECT "
303870d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong                        + RawContacts._ID + " FROM " + Tables.RAW_CONTACTS
303970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong                        + " WHERE account_name = ? AND account_type = ?)", params);
304070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong                mDb.execSQL("DELETE FROM " + Tables.RAW_CONTACTS
304170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong                        + " WHERE account_name = ? AND account_type = ?", params);
30425f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                mDb.execSQL("DELETE FROM " + Tables.SETTINGS
30435f9e610be459bd1332e182c41cf7510265d5f7ccFred Quintana                        + " WHERE account_name = ? AND account_type = ?", params);
304470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            }
30454637c20c6b6d3b6f6671e6a44ed57f1e5b9c4484Dmitri Plotnikov            mOpenHelper.getSyncState().onAccountsChanged(mDb, accounts);
304670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            mDb.setTransactionSuccessful();
304770d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        } finally {
304870d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            mDb.endTransaction();
304970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        }
305070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong    }
3051619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
3052619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
3053622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey     * Test all against {@link TextUtils#isEmpty(CharSequence)}.
3054622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey     */
3055622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    private static boolean areAllEmpty(ContentValues values, String[] keys) {
3056622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        for (String key : keys) {
3057622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            if (!TextUtils.isEmpty(values.getAsString(key))) {
3058622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                return false;
3059622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
3060622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
3061622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        return true;
3062622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    }
3063622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
30644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
30654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
30664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            String sortOrder) {
3067bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
3068bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov            Log.v(TAG, "query: " + uri);
3069bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        }
30700b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov
30714f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
307235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
3073d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
30741f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String groupBy = null;
3075c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limit = getLimit(uri);
3076c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
3077619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // TODO: Consider writing a test case for RestrictionExceptions when you
3078619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // write a new query() block to make sure it protects restricted data.
3079a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
30804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
308135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
308235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                return mOpenHelper.getSyncState().query(db, projection, selection,  selectionArgs,
308335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                        sortOrder);
308435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
3085d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
3086ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
3087619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                break;
3088619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            }
3089619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
3090d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
30914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
3092ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
30934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Contacts._ID + "=" + contactId);
30946bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
30956bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
30966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
30975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            case CONTACTS_LOOKUP:
30985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            case CONTACTS_LOOKUP_ID: {
30995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                List<String> pathSegments = uri.getPathSegments();
31005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int segmentCount = pathSegments.size();
31015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segmentCount < 3) {
31025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    throw new IllegalArgumentException("URI " + uri + " is missing a lookup key");
31035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
31045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String lookupKey = pathSegments.get(2);
31055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segmentCount == 4) {
31065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    long contactId = Long.parseLong(pathSegments.get(3));
31075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder();
31085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    setTablesAndProjectionMapForContacts(lookupQb, projection);
31095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    lookupQb.appendWhere(Contacts._ID + "=" + contactId + " AND " +
31105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            Contacts.LOOKUP_KEY + "=");
31115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    lookupQb.appendWhereEscapeString(lookupKey);
31125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    Cursor c = query(db, lookupQb, projection, selection, selectionArgs, sortOrder,
31135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            groupBy, limit);
31145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (c.getCount() != 0) {
31155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        return c;
31165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
31175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
31185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    c.close();
31195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
31205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
31215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
31225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                qb.appendWhere(Contacts._ID + "=" + lookupContactIdByLookupKey(db, lookupKey));
31235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                break;
31245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
31255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
3126ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_FILTER: {
3127ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
3128ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
31294a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
31304a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
3131e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    sb.append(Contacts._ID + " IN ");
31325e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    appendContactFilterAsNestedQuery(sb, filterParam);
31334a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(sb.toString());
3134ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
3135ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
3136ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
3137ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
3138ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_STREQUENT_FILTER:
3139ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_STREQUENT: {
31404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                String filterSql = null;
3141ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                if (match == CONTACTS_STREQUENT_FILTER
3142d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        && uri.getPathSegments().size() > 3) {
31434a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
31444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
3145e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    sb.append(Contacts._ID + " IN ");
31465e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    appendContactFilterAsNestedQuery(sb, filterParam);
31474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    filterSql = sb.toString();
31484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
31494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
3150ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
3151ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
31524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                // Build the first query for starred
31534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
31544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
3155d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
3156d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                final String starredQuery = qb.buildQuery(projection, Contacts.STARRED + "=1",
31574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
3158d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
3159d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Build the second query for frequent
3160d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                qb = new SQLiteQueryBuilder();
3161ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
31624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
31634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
3164d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
3165d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String frequentQuery = qb.buildQuery(projection,
3166d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        Contacts.TIMES_CONTACTED + " > 0 AND (" + Contacts.STARRED
3167d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        + " = 0 OR " + Contacts.STARRED + " IS NULL)",
31684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
3169d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
3170d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Put them together
3171d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery},
3172d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        STREQUENT_ORDER_BY, STREQUENT_LIMIT);
31734a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                Cursor c = db.rawQuery(query, null);
31744a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (c != null) {
3175d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                    c.setNotificationUri(getContext().getContentResolver(),
3176d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                            ContactsContract.AUTHORITY_URI);
3177d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
3178d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                return c;
3179d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar            }
3180d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
3181ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_GROUP: {
3182ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
3183b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                if (uri.getPathSegments().size() > 2) {
318471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    qb.appendWhere(CONTACTS_IN_GROUP_SELECT);
31854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
3186b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                }
3187b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                break;
3188b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            }
3189b67163a1088f09c59f324350662eb18772fac6b6Evan Millar
3190d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_DATA: {
31914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
319282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
31934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=" + contactId);
31946bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
31956bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
319600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
3197ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_PHOTO: {
31983653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
319982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
32003653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=" + contactId);
32013653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID);
32023653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                break;
32033653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov            }
32043653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
32054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case PHONES: {
320682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
320789c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
32082815f58f72f109790585931f601a63ddc02536a5Evan Millar                break;
32092815f58f72f109790585931f601a63ddc02536a5Evan Millar            }
32102815f58f72f109790585931f601a63ddc02536a5Evan Millar
321148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID: {
321282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
321348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
321448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=" + uri.getLastPathSegment());
321548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                break;
321648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            }
321748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
3218ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case PHONES_FILTER: {
321982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, true);
322089c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
3221ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
32224a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
32234a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
32245e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    sb.append("(");
32255e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
32265e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    boolean orNeeded = false;
32275e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    String normalizedName = NameNormalizer.normalize(filterParam);
32285e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    if (normalizedName.length() > 0) {
32295e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append(Data.RAW_CONTACT_ID + " IN ");
32305e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        appendRawContactsByNormalizedNameFilter(sb, normalizedName, null);
32315e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        orNeeded = true;
32325e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    }
32335e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
32345e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    if (isPhoneNumber(filterParam)) {
32355e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        if (orNeeded) {
32365e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                            sb.append(" OR ");
32375e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        }
32385e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        String number = PhoneNumberUtils.convertKeypadLettersToDigits(filterParam);
32395e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        String reversed = PhoneNumberUtils.getStrippedReversed(number);
32405e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append(Data._ID +
32415e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                                " IN (SELECT " + PhoneLookupColumns.DATA_ID
32425e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                                  + " FROM " + Tables.PHONE_LOOKUP
32435e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                                  + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '%");
32445e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append(reversed);
32455e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append("')");
32465e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    }
32475e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    sb.append(")");
32484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(" AND " + sb);
3249ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
32505e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                groupBy = PhoneColumns.NORMALIZED_NUMBER + "," + RawContacts.CONTACT_ID;
3251ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
3252ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
3253ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
32544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case EMAILS: {
325582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
325689c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
32574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                break;
32584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            }
32594a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
326048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID: {
326182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
326248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
326348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=" + uri.getLastPathSegment());
326448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                break;
326548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            }
326648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
32675e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            case EMAILS_LOOKUP: {
326882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
326989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
32704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (uri.getPathSegments().size() > 2) {
32715e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    qb.appendWhere(" AND " + Email.DATA + "=");
32724a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhereEscapeString(uri.getLastPathSegment());
32734a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
3274ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
3275ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
3276ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
32775e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            case EMAILS_FILTER: {
327882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, true);
327989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
32805e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                if (uri.getPathSegments().size() > 2) {
32815e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
32825e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
32835e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    sb.append("(");
32845e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
32855e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    String normalizedName = NameNormalizer.normalize(filterParam);
32865e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    if (normalizedName.length() > 0) {
32875e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append(Data.RAW_CONTACT_ID + " IN ");
32885e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        appendRawContactsByNormalizedNameFilter(sb, normalizedName, null);
32895e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append(" OR ");
32905e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    }
32915e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
32925e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    sb.append(Email.DATA + " LIKE ");
32931e530df9f7e496dc47f77d4323c89bd413b79b64Dmitri Plotnikov                    sb.append(DatabaseUtils.sqlEscapeString(filterParam + '%'));
32945e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    sb.append(")");
32955e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    qb.appendWhere(" AND " + sb);
32965e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                }
32975e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                groupBy = Email.DATA + "," + RawContacts.CONTACT_ID;
32985e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                break;
32995e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            }
33005e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
3301ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case POSTALS: {
330282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
330389c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '"
330489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                        + StructuredPostal.CONTENT_ITEM_TYPE + "'");
3305ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
3306ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
3307ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
330848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID: {
330982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
331048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '"
331148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                        + StructuredPostal.CONTENT_ITEM_TYPE + "'");
331248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=" + uri.getLastPathSegment());
331348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                break;
331448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            }
331548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
33165ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
33174a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getRawContactView());
3318d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sRawContactsProjectionMap);
331989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
33204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
33214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
33224f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
33235ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
33245ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
33254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getRawContactView());
3326d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sRawContactsProjectionMap);
332789c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
332889c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + RawContacts._ID + "=" + rawContactId);
33294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
33304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
33314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
33325ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
33335ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = Long.parseLong(uri.getPathSegments().get(1));
333482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
333589c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=" + rawContactId);
3336e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
3337e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
3338e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
3339e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            case DATA: {
334082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
3341e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
3342e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
3343e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
33444f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            case DATA_ID: {
334582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
334682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=" + ContentUris.parseId(uri));
3347a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov                break;
3348a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov            }
3349a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov
3350a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case PHONE_LOOKUP: {
33514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
3352a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                if (TextUtils.isEmpty(sortOrder)) {
3353a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // Default the sort order to something reasonable so we get consistent
3354a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // results when callers don't request an ordering
3355e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                    sortOrder = RawContactsColumns.CONCRETE_ID;
3356a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                }
3357a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
3358e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : "";
3359e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                mOpenHelper.buildPhoneLookupAndContactQuery(qb, number);
3360e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                qb.setProjectionMap(sPhoneLookupProjectionMap);
3361e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov
3362e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                // Phone lookup cannot be combined with a selection
3363e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                selection = null;
3364e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                selectionArgs = null;
3365a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
3366a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
3367a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
3368ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
336989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.setTables(mOpenHelper.getGroupView());
3370ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
337189c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
3372ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
3373ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
3374ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3375ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
3376ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
337789c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.setTables(mOpenHelper.getGroupView());
3378ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
337989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(Groups._ID + "=" + groupId);
3380ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
3381ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
3382ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3383ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_SUMMARY: {
338489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.setTables(mOpenHelper.getGroupView() + " AS groups");
3385ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsSummaryProjectionMap);
338689c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
338789c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                groupBy = Groups._ID;
3388ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
3389ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
3390ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3391b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
33920c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov                qb.setTables(Tables.AGGREGATION_EXCEPTIONS);
3393b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                qb.setProjectionMap(sAggregationExceptionsProjectionMap);
3394b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
3395b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
3396b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
339731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_SUGGESTIONS: {
3398d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
33992d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                String filter = null;
34002d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                if (uri.getPathSegments().size() > 3) {
34012d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                    filter = uri.getPathSegments().get(3);
34022d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                }
340331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                final int maxSuggestions;
3404d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                if (limit != null) {
3405d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                    maxSuggestions = Integer.parseInt(limit);
340631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                } else {
340731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                    maxSuggestions = DEFAULT_MAX_SUGGESTIONS;
340831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                }
340931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
34107581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
34117581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov
34127581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov                return mContactAggregator.queryAggregationSuggestions(qb, projection, contactId,
34132d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                        maxSuggestions, filter);
341431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
341531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
3416eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
3417eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                qb.setTables(Tables.SETTINGS);
3418eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                qb.setProjectionMap(sSettingsProjectionMap);
341989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
3420e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
3421e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                // When requesting specific columns, this query requires
3422e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                // late-binding of the GroupMembership MIME-type.
3423e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                final String groupMembershipMimetypeId = Long.toString(mOpenHelper
3424e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                        .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE));
342582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                if (projection != null && projection.length != 0 &&
342682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                        mOpenHelper.isInProjection(projection, Settings.UNGROUPED_COUNT)) {
3427e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                    selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId);
3428e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                }
342982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                if (projection != null && projection.length != 0 &&
343082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                        mOpenHelper.isInProjection(projection, Settings.UNGROUPED_WITH_PHONES)) {
3431e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                    selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId);
3432e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                }
3433e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
3434eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
3435eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
3436eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
343782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES: {
3438a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                qb.setTables(Tables.PRESENCE +
3439a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                        " LEFT OUTER JOIN " + Tables.STATUS_UPDATES +
344082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                        " ON(" + StatusUpdates.DATA_ID + "=" + StatusUpdatesColumns.DATA_ID + ")");
344182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                qb.setProjectionMap(sStatusUpdatesProjectionMap);
34425ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
34435ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
34445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
344582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES_ID: {
3446373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setTables(Tables.PRESENCE);
344782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                qb.setProjectionMap(sStatusUpdatesProjectionMap);
344882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                qb.appendWhere(StatusUpdates.DATA_ID + "=" + ContentUris.parseId(uri));
34495ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
34505ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
34515ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
3452c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS: {
3453a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov                return mGlobalSearchSupport.handleSearchSuggestionsQuery(db, uri, limit);
3454c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
3455c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
3456c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT: {
3457b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
3458b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                return mGlobalSearchSupport.handleSearchShortcutRefresh(db, contactId, projection);
3459c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
3460c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
34611b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS:
34621b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
34631b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
34641b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
34651b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
34661b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_WITH_PHONES:
34671b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
34681b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
34691b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1");
34701b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
34711b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
34721b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_FAVORITES:
34731b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
34741b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
34751b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(Contacts.STARRED + "=1");
34761b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
34771b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
34781b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_GROUP_NAME:
34791b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
34801b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
348171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                qb.appendWhere(CONTACTS_IN_GROUP_SELECT);
34821b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
34831b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
34841b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
34854f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            default:
3486f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.query(uri, projection, selection, selectionArgs,
3487c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                        sortOrder, limit);
34884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
34894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
34905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit);
34915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
34925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
34935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection,
34945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            String selection, String[] selectionArgs, String sortOrder, String groupBy,
34955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            String limit) {
3496038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        if (projection != null && projection.length == 1
3497038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana                && BaseColumns._COUNT.equals(projection[0])) {
3498038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            qb.setProjectionMap(sCountProjectionMap);
3499038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        }
35005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null,
35015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sortOrder, limit);
35024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        if (c != null) {
35034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI);
35044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
35054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        return c;
35064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
35074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
35085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) {
35095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        ContactLookupKey key = new ContactLookupKey();
35105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        ArrayList<LookupKeySegment> segments = key.parse(lookupKey);
35115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long contactId = lookupContactIdBySourceIds(db, segments);
35135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (contactId == -1) {
35145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            contactId = lookupContactIdByDisplayNames(db, segments);
35155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
35165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return contactId;
35185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
35195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private interface LookupBySourceIdQuery {
35215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String TABLE = Tables.RAW_CONTACTS;
35225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String COLUMNS[] = {
35245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.CONTACT_ID,
35255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
35265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
35275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.SOURCE_ID
35285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        };
35295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int CONTACT_ID = 0;
35315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_TYPE = 1;
35325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_NAME = 2;
35335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int SOURCE_ID = 3;
35345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
35355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdBySourceIds(SQLiteDatabase db,
35375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                ArrayList<LookupKeySegment> segments) {
35385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int sourceIdCount = 0;
35395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
35405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
35415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.sourceIdLookup) {
35425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sourceIdCount++;
35435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
35445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
35455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (sourceIdCount == 0) {
35475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return -1;
35485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
35495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        // First try sync ids
35515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
35525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(RawContacts.SOURCE_ID + " IN (");
35535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
35545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
35555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.sourceIdLookup) {
35565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(sb, segment.key);
35575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sb.append(",");
35585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
35595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
35605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.setLength(sb.length() - 1);      // Last comma
35615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL");
35625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS,
35645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                 sb.toString(), null, null, null, null);
35655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        try {
35665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            while (c.moveToNext()) {
35675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountType = c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE);
35685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME);
35695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int accountHashCode =
35705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        ContactLookupKey.getAccountHashCode(accountType, accountName);
35715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID);
35725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                for (int i = 0; i < segments.size(); i++) {
35735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    LookupKeySegment segment = segments.get(i);
35745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (segment.sourceIdLookup && accountHashCode == segment.accountHashCode
35755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            && segment.key.equals(sourceId)) {
35765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID);
35775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        break;
35785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
35795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
35805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
35815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } finally {
35825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            c.close();
35835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
35845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return getMostReferencedContactId(segments);
35865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
35875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private interface LookupByDisplayNameQuery {
35895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS;
35905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String COLUMNS[] = {
35925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.CONTACT_ID,
35935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
35945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
35955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                NameLookupColumns.NORMALIZED_NAME
35965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        };
35975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
35985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int CONTACT_ID = 0;
35995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_TYPE = 1;
36005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_NAME = 2;
36015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int NORMALIZED_NAME = 3;
36025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
36035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
36045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdByDisplayNames(SQLiteDatabase db,
36055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                ArrayList<LookupKeySegment> segments) {
36065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int displayNameCount = 0;
36075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
36085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
36095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (!segment.sourceIdLookup) {
36105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                displayNameCount++;
36115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
36125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
36135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
36145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (displayNameCount == 0) {
36155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return -1;
36165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
36175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
36185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        // First try sync ids
36195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
36205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(NameLookupColumns.NORMALIZED_NAME + " IN (");
36215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
36225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
36235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (!segment.sourceIdLookup) {
36245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(sb, segment.key);
36255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sb.append(",");
36265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
36275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
36285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.setLength(sb.length() - 1);      // Last comma
36295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY
36305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                + " AND " + RawContacts.CONTACT_ID + " NOT NULL");
36315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
36325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS,
36335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                 sb.toString(), null, null, null, null);
36345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        try {
36355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            while (c.moveToNext()) {
36365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountType = c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE);
36375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME);
36385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int accountHashCode =
36395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        ContactLookupKey.getAccountHashCode(accountType, accountName);
36405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME);
36415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                for (int i = 0; i < segments.size(); i++) {
36425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    LookupKeySegment segment = segments.get(i);
36435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (!segment.sourceIdLookup && accountHashCode == segment.accountHashCode
36445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            && segment.key.equals(name)) {
36455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID);
36465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        break;
36475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
36485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
36495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
36505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } finally {
36515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            c.close();
36525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
36535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
36545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return getMostReferencedContactId(segments);
36555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
36565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
36575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    /**
36585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov     * Returns the contact ID that is mentioned the highest number of times.
36595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov     */
36605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) {
36615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Collections.sort(segments);
36625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
36635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long bestContactId = -1;
36645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int bestRefCount = 0;
36655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
36665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long contactId = -1;
36675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int count = 0;
36685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
36695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int segmentCount = segments.size();
36705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segmentCount; i++) {
36715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
36725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.contactId != -1) {
36735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segment.contactId == contactId) {
36745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    count++;
36755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                } else {
36765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (count > bestRefCount) {
36775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        bestContactId = contactId;
36785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        bestRefCount = count;
36795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
36805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    contactId = segment.contactId;
36815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    count = 1;
36825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
36835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
36845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
36855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (count > bestRefCount) {
36865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return contactId;
36875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } else {
36885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return bestContactId;
36895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
36905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
36915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
3692ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, String[] projection) {
369382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
369482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sb.append(mOpenHelper.getContactView());
369582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        if (mOpenHelper.isInProjection(projection,
369682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_PRESENCE)) {
369782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE +
369882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                    " ON (" + Contacts._ID + " = " + AggregatedPresenceColumns.CONTACT_ID + ")");
369982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        }
370082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        if (mOpenHelper.isInProjection(projection,
370182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_STATUS,
370282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_STATUS_RES_PACKAGE,
370382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_STATUS_ICON,
370482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_STATUS_LABEL,
370582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Contacts.CONTACT_STATUS_TIMESTAMP)) {
370682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES +
3707a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                    " ON (" + ContactsColumns.LAST_STATUS_UPDATE_ID + "="
3708a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                            + StatusUpdatesColumns.DATA_ID + ")");
370982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        }
371082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        qb.setTables(sb.toString());
371182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        qb.setProjectionMap(sContactsProjectionMap);
371282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    }
3713ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
371482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri,
371582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            String[] projection, boolean distinct) {
371682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
371782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sb.append(mOpenHelper.getDataView());
371882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sb.append(" data");
371982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov
372082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        if (mOpenHelper.isInProjection(projection, Data.CONTACT_PRESENCE)) {
372182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE +
372282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                    " ON (" + AggregatedPresenceColumns.CONTACT_ID + "="
372382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                    + RawContacts.CONTACT_ID + ")");
372482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        }
372582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov
372682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        if (mOpenHelper.isInProjection(projection,
372782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Data.CONTACT_STATUS,
372882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Data.CONTACT_STATUS_RES_PACKAGE,
372982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Data.CONTACT_STATUS_ICON,
373082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Data.CONTACT_STATUS_LABEL,
373182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                Data.CONTACT_STATUS_TIMESTAMP)) {
373282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES +
373382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                    " ON (" + ContactsColumns.LAST_STATUS_UPDATE_ID + "="
373482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                            + StatusUpdatesColumns.DATA_ID + ")");
3735ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        }
373682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        qb.setTables(sb.toString());
373782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        qb.setProjectionMap(distinct ? sDistinctDataProjectionMap : sDataProjectionMap);
373882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        appendAccountFromParameter(qb, uri);
3739ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    }
3740ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
37414a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) {
37424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
37434a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
37444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (!TextUtils.isEmpty(accountName)) {
37454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
37464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountName) + " AND "
37474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + RawContacts.ACCOUNT_TYPE + "="
37484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountType));
37494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        } else {
37504a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere("1");
37514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        }
37524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    }
37534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
3754e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong    private String appendAccountToSelection(Uri uri, String selection) {
3755e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
3756e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
3757e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        if (!TextUtils.isEmpty(accountName)) {
3758e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "="
3759e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + DatabaseUtils.sqlEscapeString(accountName) + " AND "
3760e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + RawContacts.ACCOUNT_TYPE + "="
3761e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + DatabaseUtils.sqlEscapeString(accountType));
3762e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            if (!TextUtils.isEmpty(selection)) {
3763e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(" AND (");
3764e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(selection);
3765e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(')');
3766e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            }
3767e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            return selectionSb.toString();
3768e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        } else {
3769e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            return selection;
3770e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        }
3771e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong    }
3772e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong
37737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
3774c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * Gets the value of the "limit" URI query parameter.
3775c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *
3776c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * @return A string containing a non-negative integer, or <code>null</code> if
3777c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *         the parameter is not set, or is set to an invalid value.
3778c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     */
3779c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private String getLimit(Uri url) {
3780c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limitParam = url.getQueryParameter("limit");
3781c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limitParam == null) {
3782c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
3783c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
3784c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        // make sure that the limit is a non-negative integer
3785c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        try {
3786c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            int l = Integer.parseInt(limitParam);
3787c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            if (l < 0) {
3788c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                Log.w(TAG, "Invalid limit parameter: " + limitParam);
3789c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return null;
3790c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
3791c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return String.valueOf(l);
3792c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        } catch (NumberFormatException ex) {
3793c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            Log.w(TAG, "Invalid limit parameter: " + limitParam);
3794c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
3795c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
3796c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
3797c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
37985e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    /**
37995e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov     * Returns true if all the characters are meaningful as digits
38005e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov     * in a phone number -- letters, digits, and a few punctuation marks.
38015e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov     */
38025e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    private boolean isPhoneNumber(CharSequence cons) {
38035e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        int len = cons.length();
38045e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
38055e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        for (int i = 0; i < len; i++) {
38065e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            char c = cons.charAt(i);
38075e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
38085e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            if ((c >= '0') && (c <= '9')) {
38095e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                continue;
38105e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            }
38115e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            if ((c == ' ') || (c == '-') || (c == '(') || (c == ')') || (c == '.') || (c == '+')
38125e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    || (c == '#') || (c == '*')) {
38135e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                continue;
38145e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            }
38155e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            if ((c >= 'A') && (c <= 'Z')) {
38165e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                continue;
38175e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            }
38185e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            if ((c >= 'a') && (c <= 'z')) {
38195e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                continue;
38205e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            }
38215e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
38225e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            return false;
38235e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        }
38245e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
38255e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        return true;
38265e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    }
38275e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
382800ec508630251d6c6e3746469c9428f5a8cd5996Jeff Sharkey    String getContactsRestrictions() {
38294a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (mOpenHelper.hasRestrictedAccess()) {
383070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
383170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        } else {
38326cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            return RawContacts.IS_RESTRICTED + "=0";
383370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
383470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    }
383570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
383670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    public String getContactsRestrictionExceptionAsNestedQuery(String contactIdColumn) {
38374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (mOpenHelper.hasRestrictedAccess()) {
383870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
383967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        } else {
38405ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return "(SELECT " + RawContacts.IS_RESTRICTED + " FROM " + Tables.RAW_CONTACTS
38415ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + " WHERE " + RawContactsColumns.CONCRETE_ID + "=" + contactIdColumn + ")=0";
3842619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
3843619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
3844619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
3845b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    @Override
3846b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
3847b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        int match = sUriMatcher.match(uri);
3848b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        switch (match) {
3849d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            case CONTACTS_PHOTO: {
3850b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                if (!"r".equals(mode)) {
3851b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                    throw new FileNotFoundException("Mode " + mode + " not supported.");
3852b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                }
3853b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3854b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
3855b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3856b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                String sql =
3857b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                        "SELECT " + Photo.PHOTO + " FROM " + mOpenHelper.getDataView() +
3858b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                        " WHERE " + Data._ID + "=" + Contacts.PHOTO_ID
3859b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                                + " AND " + RawContacts.CONTACT_ID + "=" + contactId;
3860b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                SQLiteDatabase db = mOpenHelper.getReadableDatabase();
3861b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                return SQLiteContentHelper.getBlobColumnAsAssetFile(db, sql, null);
3862d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            }
3863d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
3864d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            case CONTACTS_LOOKUP:
3865d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            case CONTACTS_LOOKUP_ID: {
3866d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                // TODO: optimize lookup when direct id provided
3867d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                final String lookupKey = uri.getPathSegments().get(2);
3868d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                final long contactId = lookupContactIdByLookupKey(mDb, lookupKey);
3869d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                final String selection = RawContacts.CONTACT_ID + "=" + contactId;
3870d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
3871d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                // When opening a contact as file, we pass back contents as a
3872d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                // vCard-encoded stream. We build into a local buffer first,
3873d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                // then pipe into MemoryFile once the exact size is known.
3874d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                final ByteArrayOutputStream localStream = new ByteArrayOutputStream();
3875d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                outputRawContactsAsVCard(localStream, selection, null);
3876d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                return buildAssetFileDescriptor(localStream);
3877d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            }
3878b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3879b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov            default:
3880b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                throw new FileNotFoundException("No file at: " + uri);
3881b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        }
3882b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    }
3883b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3884d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile";
3885d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    private static final String VCARD_TYPE_DEFAULT = "default";
3886d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
3887d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    /**
3888d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * Build a {@link AssetFileDescriptor} through a {@link MemoryFile} with the
3889d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * contents of the given {@link ByteArrayOutputStream}.
3890d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     */
3891d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) {
3892d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        AssetFileDescriptor fd = null;
3893d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        try {
3894d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            stream.flush();
3895d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
3896d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            final byte[] byteData = stream.toByteArray();
3897d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            final int size = byteData.length;
3898d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
3899d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            final MemoryFile memoryFile = new MemoryFile(CONTACT_MEMORY_FILE_NAME, size);
3900d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            memoryFile.writeBytes(byteData, 0, 0, size);
3901d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            memoryFile.deactivate();
3902b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3903d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            fd = AssetFileDescriptor.fromMemoryFile(memoryFile);
3904d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        } catch (IOException e) {
3905d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            Log.w(TAG, "Problem writing stream into an AssetFileDescriptor: " + e.toString());
3906d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        }
3907d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        return fd;
3908d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    }
3909d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
3910d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    /**
3911d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * Output {@link RawContacts} matching the requested selection in the vCard
3912d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * format to the given {@link OutputStream}. This method returns silently if
3913d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * any errors encountered.
3914d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     */
3915d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    private void outputRawContactsAsVCard(OutputStream stream, String selection,
3916d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            String[] selectionArgs) {
3917d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        final Context context = this.getContext();
3918d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        final VCardComposer composer = new VCardComposer(context, VCARD_TYPE_DEFAULT, false);
3919d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        composer.addHandler(composer.new HandlerForOutputStream(stream));
3920d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
3921d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        // TODO: enforce the callers security clause is used
3922d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        if (!composer.init(selection, selectionArgs))
3923d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            return;
3924d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
3925d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        while (!composer.isAfterLast()) {
3926d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            if (!composer.createOneEntry()) {
3927d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                Log.w(TAG, "Failed to output a contact.");
3928d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            }
3929d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        }
3930d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        composer.terminate();
3931d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    }
3932b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3933bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov
3934bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov    private static Account readAccountFromQueryParams(Uri uri) {
3935bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov        final String name = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
3936bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov        final String type = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
3937bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(type)) {
3938bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov            return null;
3939bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov        }
3940bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov        return new Account(name, type);
3941bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov    }
3942bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov
3943bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov
3944619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
39457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     * An implementation of EntityIterator that joins the contacts and data tables
39467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     * and consumes all the data rows for a contact in order to build the Entity for a contact.
39477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
3948d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    private static class RawContactsEntityIterator implements EntityIterator {
39497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private final Cursor mEntityCursor;
39507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private volatile boolean mIsClosed;
39517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
39527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private static final String[] DATA_KEYS = new String[]{
39537a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA1,
39547a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA2,
39557a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA3,
39567a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA4,
39577a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA5,
39587a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA6,
39597a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA7,
39607a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA8,
39617a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA9,
39627a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA10,
39637a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA11,
39647a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA12,
39657a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA13,
39667a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA14,
39677a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA15,
39687a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC1,
39697a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC2,
39707a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC3,
39717a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC4};
39727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
39737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private static final String[] PROJECTION = new String[]{
39746cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.ACCOUNT_NAME,
39756cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
39766cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.SOURCE_ID,
39776cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.VERSION,
39786cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.DIRTY,
39797a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data._ID,
39807a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.RES_PACKAGE,
39817a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.MIMETYPE,
39827a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA1,
39837a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA2,
39847a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA3,
39857a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA4,
39867a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA5,
39877a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA6,
39887a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA7,
39897a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA8,
39907a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA9,
39917a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA10,
39927a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA11,
39937a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA12,
39947a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA13,
39957a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA14,
39967a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA15,
39977a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC1,
39987a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC2,
39997a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC3,
40007a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC4,
40017a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.RAW_CONTACT_ID,
40027a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.IS_PRIMARY,
40033cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar                Data.IS_SUPER_PRIMARY,
40047a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA_VERSION,
40057a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                GroupMembership.GROUP_SOURCE_ID,
40067a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC1,
40077a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC2,
40087a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC3,
400994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                RawContacts.SYNC4,
401038446bf47c5ee2080df69f5fc8a33ad2fa3e61b5Jeff Sharkey                RawContacts.DELETED,
4011c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey                RawContacts.CONTACT_ID,
4012c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey                RawContacts.STARRED};
4013035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana
4014035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_ACCOUNT_NAME = 0;
4015035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_ACCOUNT_TYPE = 1;
4016035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_SOURCE_ID = 2;
4017035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_VERSION = 3;
4018035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_DIRTY = 4;
4019035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_DATA_ID = 5;
402067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_RES_PACKAGE = 6;
402167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_MIMETYPE = 7;
402267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_DATA1 = 8;
40237a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_RAW_CONTACT_ID = 27;
40247a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_IS_PRIMARY = 28;
40253cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_IS_SUPER_PRIMARY = 29;
40263cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_DATA_VERSION = 30;
40273cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_GROUP_SOURCE_ID = 31;
40283cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_SYNC1 = 32;
40293cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_SYNC2 = 33;
40303cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_SYNC3 = 34;
40313cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_SYNC4 = 35;
40323cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_DELETED = 36;
40333cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_CONTACT_ID = 37;
40343cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_STARRED = 38;
40357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
4036d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        public RawContactsEntityIterator(ContactsProvider2 provider, String contactsIdString, Uri uri,
40377e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                String selection, String[] selectionArgs, String sortOrder) {
40387e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mIsClosed = false;
40397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
40407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final String updatedSortOrder = (sortOrder == null)
40417a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                    ? Data.RAW_CONTACT_ID
40427a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                    : (Data.RAW_CONTACT_ID + "," + sortOrder);
40437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
40447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase();
40457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
4046226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setTables(Tables.CONTACT_ENTITIES);
40477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (contactsIdString != null) {
40485ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.appendWhere(Data.RAW_CONTACT_ID + "=" + contactsIdString);
40497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
40506cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
40516cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
4052035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            if (!TextUtils.isEmpty(accountName)) {
405323c48e7953e2f854eeef6d8e3d3c1b901fc571edFred Quintana                if (contactsIdString != null) {
405423c48e7953e2f854eeef6d8e3d3c1b901fc571edFred Quintana                    qb.appendWhere(" AND ");
405523c48e7953e2f854eeef6d8e3d3c1b901fc571edFred Quintana                }
40566cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
4057035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                        + DatabaseUtils.sqlEscapeString(accountName) + " AND "
40586cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                        + RawContacts.ACCOUNT_TYPE + "="
4059035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                        + DatabaseUtils.sqlEscapeString(accountType));
4060035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            }
40617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs,
40627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    null, null, updatedSortOrder);
40637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor.moveToFirst();
40647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
40657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
4066038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        public void reset() throws RemoteException {
4067038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            if (mIsClosed) {
4068038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana                throw new IllegalStateException("calling reset() when the iterator is closed");
4069038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            }
4070038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            mEntityCursor.moveToFirst();
4071038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        }
4072038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana
40737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public void close() {
40747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
40757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("closing when already closed");
40767e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
40777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mIsClosed = true;
40787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor.close();
40797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
40807e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
40817e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public boolean hasNext() throws RemoteException {
40827e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
40837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("calling hasNext() when the iterator is closed");
40847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
40857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
40867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return !mEntityCursor.isAfterLast();
40877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
40887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
40897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public Entity next() throws RemoteException {
40907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
40917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("calling next() when the iterator is closed");
40927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
40937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (!hasNext()) {
40947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("you may only call next() if hasNext() is true");
40957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
40967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
40977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteCursor c = (SQLiteCursor) mEntityCursor;
40987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
40997a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            final long rawContactId = c.getLong(COLUMN_RAW_CONTACT_ID);
41007e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
41017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            // we expect the cursor is already at the row we need to read from
41027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            ContentValues contactValues = new ContentValues();
41036cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME));
41046cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE));
41055ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            contactValues.put(RawContacts._ID, rawContactId);
41066cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.DIRTY, c.getLong(COLUMN_DIRTY));
41076cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.VERSION, c.getLong(COLUMN_VERSION));
41086cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.SOURCE_ID, c.getString(COLUMN_SOURCE_ID));
41097a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC1, c.getString(COLUMN_SYNC1));
41107a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC2, c.getString(COLUMN_SYNC2));
41117a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC3, c.getString(COLUMN_SYNC3));
41127a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC4, c.getString(COLUMN_SYNC4));
411394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            contactValues.put(RawContacts.DELETED, c.getLong(COLUMN_DELETED));
411438446bf47c5ee2080df69f5fc8a33ad2fa3e61b5Jeff Sharkey            contactValues.put(RawContacts.CONTACT_ID, c.getLong(COLUMN_CONTACT_ID));
4115c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey            contactValues.put(RawContacts.STARRED, c.getLong(COLUMN_STARRED));
41167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            Entity contact = new Entity(contactValues);
41177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
41187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            // read data rows until the contact id changes
41197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            do {
41207a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                if (rawContactId != c.getLong(COLUMN_RAW_CONTACT_ID)) {
41217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    break;
41227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
412323c48e7953e2f854eeef6d8e3d3c1b901fc571edFred Quintana//                if (c.isNull(COLUMN_CONTACT_ID)) {
412423c48e7953e2f854eeef6d8e3d3c1b901fc571edFred Quintana//                    continue;
412523c48e7953e2f854eeef6d8e3d3c1b901fc571edFred Quintana//                }
41267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                // add the data to to the contact
41277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                ContentValues dataValues = new ContentValues();
412823c48e7953e2f854eeef6d8e3d3c1b901fc571edFred Quintana                dataValues.put(Data._ID, c.getLong(COLUMN_DATA_ID));
41297a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.RES_PACKAGE, c.getString(COLUMN_RES_PACKAGE));
41307a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.MIMETYPE, c.getString(COLUMN_MIMETYPE));
413123c48e7953e2f854eeef6d8e3d3c1b901fc571edFred Quintana                dataValues.put(Data.IS_PRIMARY, c.getLong(COLUMN_IS_PRIMARY));
413223c48e7953e2f854eeef6d8e3d3c1b901fc571edFred Quintana                dataValues.put(Data.IS_SUPER_PRIMARY, c.getLong(COLUMN_IS_SUPER_PRIMARY));
41337a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION));
41349261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (!c.isNull(COLUMN_GROUP_SOURCE_ID)) {
41359261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    dataValues.put(GroupMembership.GROUP_SOURCE_ID,
41369261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            c.getString(COLUMN_GROUP_SOURCE_ID));
41379261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
41387a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION));
41397a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                for (int i = 0; i < DATA_KEYS.length; i++) {
41407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    final int columnIndex = i + COLUMN_DATA1;
41417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    String key = DATA_KEYS[i];
41427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    if (c.isNull(columnIndex)) {
41437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        // don't put anything
41447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isLong(columnIndex)) {
41457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getLong(columnIndex));
41467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isFloat(columnIndex)) {
41477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getFloat(columnIndex));
41487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isString(columnIndex)) {
41497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getString(columnIndex));
41507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isBlob(columnIndex)) {
41517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getBlob(columnIndex));
41527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    }
41537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
41547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                contact.addSubValue(Data.CONTENT_URI, dataValues);
41557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            } while (mEntityCursor.moveToNext());
41567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
41577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return contact;
41587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
41597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
41607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
4161226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    /**
4162226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     * An implementation of EntityIterator that joins the contacts and data tables
4163226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     * and consumes all the data rows for a contact in order to build the Entity for a contact.
4164226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     */
4165226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    private static class GroupsEntityIterator implements EntityIterator {
4166226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private final Cursor mEntityCursor;
4167226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private volatile boolean mIsClosed;
4168226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4169226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final String[] PROJECTION = new String[]{
4170226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups._ID,
4171226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.ACCOUNT_NAME,
4172226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.ACCOUNT_TYPE,
4173226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.SOURCE_ID,
4174226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.DIRTY,
4175226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.VERSION,
4176226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.RES_PACKAGE,
4177226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.TITLE,
4178226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.TITLE_RES,
41797a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.GROUP_VISIBLE,
41807a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC1,
41817a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC2,
41827a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC3,
41837a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC4,
41847a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYSTEM_ID,
418594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                Groups.NOTES,
41861a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey                Groups.DELETED,
41871a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey                Groups.SHOULD_SYNC};
4188226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4189226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ID = 0;
4190226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ACCOUNT_NAME = 1;
4191226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ACCOUNT_TYPE = 2;
4192226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_SOURCE_ID = 3;
4193226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_DIRTY = 4;
4194226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_VERSION = 5;
4195226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_RES_PACKAGE = 6;
4196226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_TITLE = 7;
4197226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_TITLE_RES = 8;
4198226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_GROUP_VISIBLE = 9;
41997a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC1 = 10;
42007a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC2 = 11;
42017a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC3 = 12;
42027a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC4 = 13;
42037a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYSTEM_ID = 14;
42047a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_NOTES = 15;
420594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        private static final int COLUMN_DELETED = 16;
42061a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        private static final int COLUMN_SHOULD_SYNC = 17;
4207226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4208226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public GroupsEntityIterator(ContactsProvider2 provider, String groupIdString, Uri uri,
4209226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                String selection, String[] selectionArgs, String sortOrder) {
4210226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mIsClosed = false;
4211226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4212226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String updatedSortOrder = (sortOrder == null)
4213226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    ? Groups._ID
4214226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    : (Groups._ID + "," + sortOrder);
4215226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4216226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase();
4217226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
421889c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov            qb.setTables(provider.mOpenHelper.getGroupView());
4219226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setProjectionMap(sGroupsProjectionMap);
4220226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (groupIdString != null) {
4221226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                qb.appendWhere(Groups._ID + "=" + groupIdString);
4222226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
4223226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String accountName = uri.getQueryParameter(Groups.ACCOUNT_NAME);
4224226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String accountType = uri.getQueryParameter(Groups.ACCOUNT_TYPE);
4225226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (!TextUtils.isEmpty(accountName)) {
4226226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                qb.appendWhere(Groups.ACCOUNT_NAME + "="
4227226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + DatabaseUtils.sqlEscapeString(accountName) + " AND "
4228226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + Groups.ACCOUNT_TYPE + "="
4229226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + DatabaseUtils.sqlEscapeString(accountType));
4230226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
4231226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs,
4232226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    null, null, updatedSortOrder);
4233226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.moveToFirst();
4234226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
4235226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4236226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public void close() {
4237226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
4238226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("closing when already closed");
4239226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
4240226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mIsClosed = true;
4241226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.close();
4242226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
4243226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4244226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public boolean hasNext() throws RemoteException {
4245226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
4246226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("calling hasNext() when the iterator is closed");
4247226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
4248226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4249226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            return !mEntityCursor.isAfterLast();
4250226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
4251226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4252038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        public void reset() throws RemoteException {
4253038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            if (mIsClosed) {
4254038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana                throw new IllegalStateException("calling reset() when the iterator is closed");
4255038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            }
4256038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            mEntityCursor.moveToFirst();
4257038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        }
4258e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
4259226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public Entity next() throws RemoteException {
4260226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
4261226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("calling next() when the iterator is closed");
4262226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
4263226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (!hasNext()) {
4264226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("you may only call next() if hasNext() is true");
4265226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
4266226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4267226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteCursor c = (SQLiteCursor) mEntityCursor;
4268226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4269226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final long groupId = c.getLong(COLUMN_ID);
4270226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4271226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            // we expect the cursor is already at the row we need to read from
4272226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            ContentValues groupValues = new ContentValues();
4273226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME));
4274226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE));
4275226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups._ID, groupId);
4276226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.DIRTY, c.getLong(COLUMN_DIRTY));
4277226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.VERSION, c.getLong(COLUMN_VERSION));
4278226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.SOURCE_ID, c.getString(COLUMN_SOURCE_ID));
4279226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.RES_PACKAGE, c.getString(COLUMN_RES_PACKAGE));
4280226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.TITLE, c.getString(COLUMN_TITLE));
4281226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.TITLE_RES, c.getString(COLUMN_TITLE_RES));
4282226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.GROUP_VISIBLE, c.getLong(COLUMN_GROUP_VISIBLE));
42837a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC1, c.getString(COLUMN_SYNC1));
42847a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC2, c.getString(COLUMN_SYNC2));
42857a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC3, c.getString(COLUMN_SYNC3));
42867a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC4, c.getString(COLUMN_SYNC4));
42877a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYSTEM_ID, c.getString(COLUMN_SYSTEM_ID));
428894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            groupValues.put(Groups.DELETED, c.getLong(COLUMN_DELETED));
42897a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.NOTES, c.getString(COLUMN_NOTES));
42901a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            groupValues.put(Groups.SHOULD_SYNC, c.getString(COLUMN_SHOULD_SYNC));
4291226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            Entity group = new Entity(groupValues);
4292226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4293226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.moveToNext();
4294226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4295226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            return group;
4296226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
4297226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    }
4298226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4299a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    @Override
43007e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
43017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            String sortOrder) {
4302568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
4303568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
43047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        final int match = sUriMatcher.match(uri);
43057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        switch (match) {
43065ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS:
43075ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID:
43087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                String contactsIdString = null;
43095ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                if (match == RAW_CONTACTS_ID) {
43107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    contactsIdString = uri.getPathSegments().get(1);
43117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
43127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
4313d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                return new RawContactsEntityIterator(this, contactsIdString,
43147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        uri, selection, selectionArgs, sortOrder);
4315226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            case GROUPS:
4316226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            case GROUPS_ID:
4317226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                String idString = null;
4318226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                if (match == GROUPS_ID) {
4319226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    idString = uri.getPathSegments().get(1);
4320226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                }
4321226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
4322226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                return new GroupsEntityIterator(this, idString,
4323226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        uri, selection, selectionArgs, sortOrder);
43247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            default:
43257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new UnsupportedOperationException("Unknown uri: " + uri);
43267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
43277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
43287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
43294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
43304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public String getType(Uri uri) {
4331a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
43324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
4333b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS:
4334b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS_LOOKUP:
4335be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov                return Contacts.CONTENT_TYPE;
4336b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS_ID:
4337b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS_LOOKUP_ID:
4338b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Contacts.CONTENT_ITEM_TYPE;
4339b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case RAW_CONTACTS:
4340be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov                return RawContacts.CONTENT_TYPE;
4341b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case RAW_CONTACTS_ID:
4342b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return RawContacts.CONTENT_ITEM_TYPE;
4343508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            case DATA_ID:
4344b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return mOpenHelper.getDataMimeType(ContentUris.parseId(uri));
434548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES:
434648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Phone.CONTENT_TYPE;
434748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID:
434848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Phone.CONTENT_ITEM_TYPE;
434948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS:
435048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Email.CONTENT_TYPE;
435148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID:
435248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Email.CONTENT_ITEM_TYPE;
435348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS:
435448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return StructuredPostal.CONTENT_TYPE;
435548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID:
435648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return StructuredPostal.CONTENT_ITEM_TYPE;
4357b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_EXCEPTIONS:
4358b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return AggregationExceptions.CONTENT_TYPE;
4359b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_EXCEPTION_ID:
4360b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return AggregationExceptions.CONTENT_ITEM_TYPE;
4361b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case SETTINGS:
4362b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Settings.CONTENT_TYPE;
4363b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_SUGGESTIONS:
4364b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Contacts.CONTENT_TYPE;
4365c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS:
4366c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SUGGEST_MIME_TYPE;
4367c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT:
4368c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SHORTCUT_MIME_TYPE;
436961efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov            default:
437061efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov                return mLegacyApiSupport.getType(uri);
43714f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
43724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
43737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
437425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov    private void setDisplayName(long rawContactId, String displayName, int bestDisplayNameSource) {
43753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (displayName != null) {
437625abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            mRawContactDisplayNameUpdate.bindString(1, displayName);
43773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        } else {
437825abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            mRawContactDisplayNameUpdate.bindNull(1);
43793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
438025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        mRawContactDisplayNameUpdate.bindLong(2, bestDisplayNameSource);
438125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        mRawContactDisplayNameUpdate.bindLong(3, rawContactId);
438225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        mRawContactDisplayNameUpdate.execute();
43833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
43843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
438573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /**
438673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Sets the {@link RawContacts#DIRTY} for the specified raw contact.
438773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     */
438873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private void setRawContactDirty(long rawContactId) {
438973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate.bindLong(1, rawContactId);
439073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate.execute();
439173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    }
439273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
4393c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
4394c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to primary, and resets all data records of
4395c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * the same mimetype and under the same contact to not be primary.
4396c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
4397c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
4398c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
4399653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    private void setIsPrimary(long rawContactId, long dataId, long mimeTypeId) {
4400c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.bindLong(1, dataId);
4401653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetPrimaryStatement.bindLong(2, mimeTypeId);
4402653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetPrimaryStatement.bindLong(3, rawContactId);
4403c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.execute();
4404c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
4405c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
4406c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
4407c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to "super primary", and resets all data
4408c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * records of the same mimetype and under the same aggregate to not be "super primary".
4409c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
4410c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
4411c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
4412653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    private void setIsSuperPrimary(long rawContactId, long dataId, long mimeTypeId) {
4413c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.bindLong(1, dataId);
4414653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetSuperPrimaryStatement.bindLong(2, mimeTypeId);
4415653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetSuperPrimaryStatement.bindLong(3, rawContactId);
4416c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.execute();
4417c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
4418ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
4419f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    public void insertNameLookupForEmail(long rawContactId, long dataId, String email) {
4420f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (TextUtils.isEmpty(email)) {
4421f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            return;
4422f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
4423f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4424f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(email);
4425f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (tokens.length == 0) {
4426f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            return;
4427f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
4428f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4429f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        String address = tokens[0].getAddress();
4430f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        int at = address.indexOf('@');
4431f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (at != -1) {
4432f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            address = address.substring(0, at);
4433f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
4434f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4435f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        insertNameLookup(rawContactId, dataId,
4436f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                NameLookupType.EMAIL_BASED_NICKNAME, NameNormalizer.normalize(address));
4437f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
4438f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4439f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    /**
4440f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     * Normalizes the nickname and inserts it in the name lookup table.
4441f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     */
4442f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    public void insertNameLookupForNickname(long rawContactId, long dataId, String nickname) {
4443f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (TextUtils.isEmpty(nickname)) {
4444f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            return;
4445f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
4446f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4447f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        insertNameLookup(rawContactId, dataId,
4448f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                NameLookupType.NICKNAME, NameNormalizer.normalize(nickname));
4449f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
4450f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4451a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka    public void insertNameLookupForOrganization(long rawContactId, long dataId, String company,
4452a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            String title) {
4453a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        if (!TextUtils.isEmpty(company)) {
4454a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            insertNameLookup(rawContactId, dataId,
4455a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    NameLookupType.ORGANIZATION, NameNormalizer.normalize(company));
4456a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        }
4457a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        if (!TextUtils.isEmpty(title)) {
4458a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            insertNameLookup(rawContactId, dataId,
4459a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    NameLookupType.ORGANIZATION, NameNormalizer.normalize(title));
4460a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        }
4461a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka    }
4462f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4463f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    public void insertNameLookupForStructuredName(long rawContactId, long dataId, String name) {
4464f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        mNameLookupBuilder.insertNameLookup(rawContactId, dataId, name);
4465f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
4466f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4467f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    /**
4468f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     * Returns nickname cluster IDs or null. Maintains cache.
4469f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     */
4470f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    protected String[] getCommonNicknameClusters(String normalizedName) {
4471f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        SoftReference<String[]> ref;
4472f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        String[] clusters = null;
4473f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        synchronized (mNicknameClusterCache) {
4474f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            if (mNicknameClusterCache.containsKey(normalizedName)) {
4475f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                ref = mNicknameClusterCache.get(normalizedName);
4476f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                if (ref == null) {
4477f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                    return null;
4478f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                }
4479f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                clusters = ref.get();
4480f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            }
4481f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
4482f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4483f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (clusters == null) {
4484f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            clusters = loadNicknameClusters(normalizedName);
4485f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            ref = clusters == null ? null : new SoftReference<String[]>(clusters);
4486f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            synchronized (mNicknameClusterCache) {
4487f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                mNicknameClusterCache.put(normalizedName, ref);
4488f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            }
4489f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
4490f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        return clusters;
4491f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
4492f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4493f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    protected String[] loadNicknameClusters(String normalizedName) {
4494f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
4495f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        String[] clusters = null;
4496f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        Cursor cursor = db.query(NicknameLookupQuery.TABLE, NicknameLookupQuery.COLUMNS,
4497f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                NicknameLookupColumns.NAME + "=?", new String[] { normalizedName },
4498f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                null, null, null);
4499f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        try {
4500f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            int count = cursor.getCount();
4501f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            if (count > 0) {
4502f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                clusters = new String[count];
4503f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                for (int i = 0; i < count; i++) {
4504f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                    cursor.moveToNext();
4505f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                    clusters[i] = cursor.getString(NicknameLookupQuery.CLUSTER);
4506f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                }
4507f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            }
4508f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        } finally {
4509f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            cursor.close();
4510f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
4511f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        return clusters;
4512f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
4513f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4514f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private class StructuredNameLookupBuilder extends NameLookupBuilder {
4515f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4516f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        public StructuredNameLookupBuilder(NameSplitter splitter) {
4517f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            super(splitter);
4518f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
4519f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4520f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        @Override
4521f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        protected void insertNameLookup(long rawContactId, long dataId, int lookupType,
4522f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                String name) {
4523f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            ContactsProvider2.this.insertNameLookup(rawContactId, dataId, lookupType, name);
4524f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
4525f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4526f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        @Override
4527f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        protected String[] getCommonNicknameClusters(String normalizedName) {
4528f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            return ContactsProvider2.this.getCommonNicknameClusters(normalizedName);
4529f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
4530f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
4531f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4532f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    /**
4533f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     * Inserts a record in the {@link Tables#NAME_LOOKUP} table.
4534f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     */
4535f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    public void insertNameLookup(long rawContactId, long dataId, int lookupType, String name) {
4536f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 1, rawContactId);
4537f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 2, dataId);
4538f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 3, lookupType);
4539f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 4, name);
4540f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        mNameLookupInsert.executeInsert();
4541f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
4542f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
4543f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    /**
4544f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     * Deletes all {@link Tables#NAME_LOOKUP} table rows associated with the specified data element.
4545f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     */
4546f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    public void deleteNameLookup(long dataId) {
4547f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        DatabaseUtils.bindObjectToProgram(mNameLookupDelete, 1, dataId);
4548f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        mNameLookupDelete.execute();
4549f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
4550f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
45512d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov    public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) {
4552d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov        sb.append("(" +
4553d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                "SELECT DISTINCT " + RawContacts.CONTACT_ID +
4554d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " FROM " + Tables.RAW_CONTACTS +
4555d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " JOIN " + Tables.NAME_LOOKUP +
4556d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " ON(" + RawContactsColumns.CONCRETE_ID + "="
4557d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                        + NameLookupColumns.RAW_CONTACT_ID + ")" +
4558d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " WHERE normalized_name GLOB '");
4559e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        sb.append(NameNormalizer.normalize(filterParam));
4560d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov        sb.append("*' AND " + NameLookupColumns.NAME_TYPE + " IN("
4561d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                + NameLookupType.NAME_COLLATION_KEY + ","
4562d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                + NameLookupType.EMAIL_BASED_NICKNAME + ","
4563d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                + NameLookupType.NICKNAME + ","
4564d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                + NameLookupType.ORGANIZATION + "))");
4565e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    }
4566e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
45675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public String getRawContactsByFilterAsNestedQuery(String filterParam) {
4568c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        StringBuilder sb = new StringBuilder();
4569c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        appendRawContactsByFilterAsNestedQuery(sb, filterParam, null);
4570c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        return sb.toString();
4571c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
4572c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
4573a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    public void appendRawContactsByFilterAsNestedQuery(StringBuilder sb, String filterParam,
4574c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            String limit) {
45755e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        appendRawContactsByNormalizedNameFilter(sb, NameNormalizer.normalize(filterParam), limit);
45765e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    }
45775e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
45785e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    private void appendRawContactsByNormalizedNameFilter(StringBuilder sb, String normalizedName,
45795e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            String limit) {
4580d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov        sb.append("(" +
4581d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                "SELECT DISTINCT " + NameLookupColumns.RAW_CONTACT_ID +
4582d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " FROM " + Tables.NAME_LOOKUP +
4583d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " WHERE " + NameLookupColumns.NORMALIZED_NAME +
4584d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " GLOB '");
45855e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        sb.append(normalizedName);
4586a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        sb.append("*' AND " + NameLookupColumns.NAME_TYPE + " IN ("
4587a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                + NameLookupType.NAME_COLLATION_KEY + ","
4588a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                + NameLookupType.NICKNAME + ","
4589d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                + NameLookupType.EMAIL_BASED_NICKNAME + ","
4590a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                + NameLookupType.ORGANIZATION + ")");
45913de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikov
4592c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limit != null) {
4593c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            sb.append(" LIMIT ").append(limit);
4594c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
4595c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append(")");
4596ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    }
4597ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
45984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /**
45994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     * Inserts an argument at the beginning of the selection arg list.
46004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     */
46014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private String[] insertSelectionArg(String[] selectionArgs, String arg) {
4602b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        if (selectionArgs == null) {
4603b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return new String[] {arg};
4604b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        } else {
4605b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            int newLength = selectionArgs.length + 1;
4606b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            String[] newSelectionArgs = new String[newLength];
46074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            newSelectionArgs[0] = arg;
46084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length);
4609b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return newSelectionArgs;
4610b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        }
4611b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    }
4612caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
4613caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    protected Account getDefaultAccount() {
4614caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        AccountManager accountManager = AccountManager.get(getContext());
4615caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        try {
4616df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana            Account[] accounts = accountManager.getAccountsByTypeAndFeatures(DEFAULT_ACCOUNT_TYPE,
4617df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                    new String[] {FEATURE_LEGACY_HOSTED_OR_GOOGLE}, null, null).getResult();
4618caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            if (accounts != null && accounts.length > 0) {
4619caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov                return accounts[0];
4620caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            }
4621caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        } catch (Throwable e) {
46226f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov            Log.e(TAG, "Cannot determine the default account for contacts compatibility", e);
4623caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        }
46246f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov        return null;
4625caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    }
46264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton}
4627