ContactsProvider2.java revision a6733943584294492aa0118fc32bf4e58dabb028
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
1967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport com.android.internal.content.SyncStateContentProviderHelper;
205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport com.android.providers.contacts.ContactLookupKey.LookupKeySegment;
21e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.AggregatedPresenceColumns;
2228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.AggregationExceptionColumns;
2328f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.Clauses;
24d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.ContactsColumns;
2528f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.DataColumns;
2628f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.GroupsColumns;
2728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.MimetypesColumns;
2811944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.NameLookupColumns;
295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.NameLookupType;
3067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport com.android.providers.contacts.OpenHelper.PackagesColumns;
31d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.PhoneColumns;
3228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.PhoneLookupColumns;
334dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.PresenceColumns;
34d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.RawContactsColumns;
3528f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.Tables;
36e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikovimport com.google.android.collect.Lists;
37e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
38b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account;
39caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikovimport android.accounts.AccountManager;
40c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager;
41568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderOperation;
42568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderResult;
4335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris;
4467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues;
4567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context;
4635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.Entity;
4767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.EntityIterator;
48568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.OperationApplicationException;
493d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences;
5067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher;
513d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences.Editor;
52b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.content.res.AssetFileDescriptor;
534f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor;
54ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils;
55b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.database.sqlite.SQLiteContentHelper;
56b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.database.sqlite.SQLiteCursor;
574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase;
584f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder;
59c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millarimport android.database.sqlite.SQLiteStatement;
604f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri;
61b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException;
623d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager;
63508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns;
64de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract;
651b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikovimport android.provider.LiveFolders;
66b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions;
67de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds;
68d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
69de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Data;
70ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.Groups;
71e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikovimport android.provider.ContactsContract.PhoneLookup;
721f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkeyimport android.provider.ContactsContract.Presence;
73d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
74eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkeyimport android.provider.ContactsContract.Settings;
753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.BaseTypes;
76ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Email;
77ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im;
793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname;
803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization;
81de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds.Phone;
82b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Photo;
834097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
8467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
85a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils;
86a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils;
87c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log;
884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
89b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport java.io.FileNotFoundException;
907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList;
915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.Collections;
92b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap;
935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.List;
94ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch;
954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/**
974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications
984f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}.
994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */
100de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikovpublic class ContactsProvider2 extends SQLiteContentProvider {
101caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
102b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    // TODO: clean up debug tag and rename this class
103b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private static final String TAG = "ContactsProvider ~~~~";
1044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
105619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: carefully prevent all incoming nested queries; they can be gaping security holes
106619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: check for restricted flag during insert(), update(), and delete() calls
107619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
1083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Default for the maximum number of returned aggregation suggestions. */
1093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DEFAULT_MAX_SUGGESTIONS = 5;
1103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1113d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /**
1123d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * Shared preference key for the legacy contact import version. The need for a version
1133d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * as opposed to a boolean flag is that if we discover bugs in the contact import process,
1143d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * we can trigger re-import by incrementing the import version.
1153d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     */
1163d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private static final String PREF_CONTACTS_IMPORTED = "contacts_imported_v1";
1173d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private static final int PREF_CONTACTS_IMPORT_VERSION = 1;
1183d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
119a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
1204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
121d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, "
122d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.TIMES_CONTACTED + " DESC, "
123d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.DISPLAY_NAME + " ASC";
124d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar    private static final String STREQUENT_LIMIT =
125d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE "
126d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.STARRED + "=1) + 25";
127d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov
128d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS = 1000;
129d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS_ID = 1001;
1305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_LOOKUP = 1002;
1315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_LOOKUP_ID = 1003;
1325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_DATA = 1004;
1335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_FILTER = 1005;
1345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_STREQUENT = 1006;
1355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_STREQUENT_FILTER = 1007;
1365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_GROUP = 1008;
1375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_PHOTO = 1009;
1384f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1395ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS = 2002;
1405ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_ID = 2003;
1415ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_DATA = 2004;
1424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1436bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA = 3000;
1446bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA_ID = 3001;
145ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int PHONES = 3002;
146ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int PHONES_FILTER = 3003;
1474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final int EMAILS = 3004;
1484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final int EMAILS_FILTER = 3005;
1494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final int POSTALS = 3006;
150a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1516bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int PHONE_LOOKUP = 4000;
1526bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
153b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTIONS = 6000;
154b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTION_ID = 6001;
155b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
1561f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    private static final int PRESENCE = 7000;
1571f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    private static final int PRESENCE_ID = 7001;
1581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
15931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    private static final int AGGREGATION_SUGGESTIONS = 8000;
16031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
161eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    private static final int SETTINGS = 9000;
162eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
163ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS = 10000;
164ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_ID = 10001;
165ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_SUMMARY = 10003;
166ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
16735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana    private static final int SYNCSTATE = 11000;
16835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
169c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SUGGESTIONS = 12001;
170c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SHORTCUT = 12002;
171c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
172a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov    private static final int DATA_WITH_PRESENCE = 13000;
17319a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
1741b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS = 14000;
1751b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_WITH_PHONES = 14001;
1761b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002;
1771b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003;
1781b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
17967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    private interface ContactsQuery {
1805ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final String TABLE = Tables.RAW_CONTACTS;
1819261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
18267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
1836cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
1846cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.ACCOUNT_NAME,
1856cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.ACCOUNT_TYPE,
186ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
187ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1885ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
18967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int ACCOUNT_NAME = 1;
19067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int ACCOUNT_TYPE = 2;
19167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    }
19267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
193d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private interface DataContactsQuery {
194d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS;
19567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
19667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
1976cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
1983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
199d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            ContactsColumns.CONCRETE_ID,
2003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.CONCRETE_ID,
201ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
202ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
203d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
20467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA_ID = 1;
205d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int CONTACT_ID = 2;
20667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int MIMETYPE_ID = 3;
207ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
2081f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private interface DisplayNameQuery {
21067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
2113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final String[] COLUMNS = new String[] {
2133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
2143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
2153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA2,
2163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            StructuredName.DISPLAY_NAME,
2173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
2183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 0;
2203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 1;
2213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA2 = 2;
2223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DISPLAY_NAME = 3;
2233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
2243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
22514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    private interface DataDeleteQuery {
22667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
2273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
22888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] CONCRETE_COLUMNS = new String[] {
2293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
2303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
2315ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Data.RAW_CONTACT_ID,
2323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
2333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA2,
23488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        };
23588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov
23688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] COLUMNS = new String[] {
23788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data._ID,
23888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            MimetypesColumns.MIMETYPE,
23988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.RAW_CONTACT_ID,
24088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.IS_PRIMARY,
24188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.DATA2,
2423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
2433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
24414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public static final int _ID = 0;
2453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 1;
2465ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 2;
2473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 3;
24888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final int DATA2 = 4;
2493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
2503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
25114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    private interface DataUpdateQuery {
252321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        String[] COLUMNS = { Data._ID, Data.RAW_CONTACT_ID, Data.MIMETYPE };
25320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
25420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int _ID = 0;
255321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int RAW_CONTACT_ID = 1;
256321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int MIMETYPE = 2;
25720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
25820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    // Higher number represents higher priority in choosing what data to use for the display name
2603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_EMAIL = 1;
2613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_PHONE = 2;
2623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_ORGANIZATION = 3;
2633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_STRUCTURED_NAME = 4;
2643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final HashMap<String, Integer> sDisplayNamePriorities;
2663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    static {
2673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities = new HashMap<String, Integer>();
2683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(StructuredName.CONTENT_ITEM_TYPE,
2693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_STRUCTURED_NAME);
2703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(Organization.CONTENT_ITEM_TYPE,
2713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_ORGANIZATION);
2723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(Phone.CONTENT_ITEM_TYPE,
2733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_PHONE);
2743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(Email.CONTENT_ITEM_TYPE,
2753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_EMAIL);
2763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
27731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
278caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    public static final String DEFAULT_ACCOUNT_TYPE = "com.google.GAIA";
279df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana    public static final String FEATURE_LEGACY_HOSTED_OR_GOOGLE = "legacy_hosted_or_google";
280caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
281038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana    /** Contains just BaseColumns._COUNT */
282038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana    private static final HashMap<String, String> sCountProjectionMap;
283e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov    /** Contains just the contacts columns */
2844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    private static final HashMap<String, String> sContactsProjectionMap;
285ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    /** Contains contacts and presence columns */
286ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    private static final HashMap<String, String> sContactsWithPresenceProjectionMap;
287ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    /** Contains just the raw contacts columns */
288d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final HashMap<String, String> sRawContactsProjectionMap;
2894a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /** Contains columns from the data view */
2904a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final HashMap<String, String> sDataProjectionMap;
2919261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /** Contains the data and contacts columns, for joined tables */
292e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov    private static final HashMap<String, String> sPhoneLookupProjectionMap;
293ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains the just the {@link Groups} columns */
294ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsProjectionMap;
295ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains {@link Groups} columns along with summary details */
296ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsSummaryProjectionMap;
297373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    /** Contains the agg_exceptions columns */
298b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final HashMap<String, String> sAggregationExceptionsProjectionMap;
299eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    /** Contains the agg_exceptions columns */
300eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    private static final HashMap<String, String> sSettingsProjectionMap;
301373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    /** Contains Presence columns */
302373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    private static final HashMap<String, String> sPresenceProjectionMap;
30319a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov    /** Contains Presence columns */
304a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov    private static final HashMap<String, String> sDataWithPresenceProjectionMap;
3051b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    /** Contains Live Folders columns */
3061b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final HashMap<String, String> sLiveFoldersProjectionMap;
3077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
308b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    /** Sql where statement for filtering on groups. */
309d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String sContactsInGroupSelect;
31019a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
311c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Precompiled sql statement for setting a data record to the primary. */
312c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetPrimaryStatement;
3133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for setting a data record to the super primary. */
314c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetSuperPrimaryStatement;
315d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Precompiled sql statement for incrementing times contacted for an contact */
316f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private SQLiteStatement mLastTimeContactedUpdate;
3173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for updating a contact display name */
3183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private SQLiteStatement mContactDisplayNameUpdate;
31973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /** Precompiled sql statement for marking a raw contact as dirty */
32073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private SQLiteStatement mRawContactDirtyUpdate;
321e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    /** Precompiled sql statement for setting an aggregated presence */
322e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    private SQLiteStatement mAggregatedPresenceReplace;
323e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    /** Precompiled sql statement for updating an aggregated presence status */
324e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    private SQLiteStatement mAggregatedPresenceStatusUpdate;
325a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
3264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    static {
3274f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        // Contacts URI matching table
328a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final UriMatcher matcher = sUriMatcher;
329d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS);
330d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
331d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_DATA);
3323653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions",
3333653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                AGGREGATION_SUGGESTIONS);
3343653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_PHOTO);
3355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER);
3365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP);
3375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID);
3385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT);
339ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*",
340ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                CONTACTS_STREQUENT_FILTER);
3415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP);
3423653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
3435ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
3445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID);
3455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA);
346b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
3474f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);
3484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID);
349ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES);
350ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER);
3514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS);
3524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER);
353ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS);
3541f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
355ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS);
356ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID);
357ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY);
358ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
35935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE);
36035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
361a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP);
362b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions",
363b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTIONS);
364b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*",
365b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTION_ID);
3664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
367eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS);
368eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
369bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "presence", PRESENCE);
370bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "presence/#", PRESENCE_ID);
3711f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
372c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
373c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
374c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
375c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
376c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/#",
377c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SHORTCUT);
378c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
3791b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts",
3801b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS);
3811b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*",
3821b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_GROUP_NAME);
3831b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones",
3841b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_WITH_PHONES);
3851b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites",
3861b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_FAVORITES);
3871b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
38819a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov        // Private API
389a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data_with_presence", DATA_WITH_PRESENCE);
39019a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov    }
39119a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
39219a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov    static {
393038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        sCountProjectionMap = new HashMap<String, String>();
394038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        sCountProjectionMap.put(BaseColumns._COUNT, "COUNT(*)");
395e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
3964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap = new HashMap<String, String>();
3974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts._ID, Contacts._ID);
3984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME);
3994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
4004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
4014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
4024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.IN_VISIBLE_GROUP, Contacts.IN_VISIBLE_GROUP);
4034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
4044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
405f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov        sContactsProjectionMap.put(Contacts.HAS_PHONE_NUMBER, Contacts.HAS_PHONE_NUMBER);
4064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
4075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sContactsProjectionMap.put(Contacts.LOOKUP_KEY, Contacts.LOOKUP_KEY);
4084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
409ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        sContactsWithPresenceProjectionMap = new HashMap<String, String>();
410ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        sContactsWithPresenceProjectionMap.putAll(sContactsProjectionMap);
411ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        sContactsWithPresenceProjectionMap.put(Contacts.PRESENCE_STATUS,
412e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                Presence.PRESENCE_STATUS + " AS " + Contacts.PRESENCE_STATUS);
413ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        sContactsWithPresenceProjectionMap.put(Contacts.PRESENCE_CUSTOM_STATUS,
414ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                Presence.PRESENCE_CUSTOM_STATUS + " AS " + Contacts.PRESENCE_CUSTOM_STATUS);
4154a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
4164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap = new HashMap<String, String>();
4174a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts._ID, RawContacts._ID);
4184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
4194a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
4204a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
4214a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
4224a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.VERSION, RawContacts.VERSION);
4234a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DIRTY, RawContacts.DIRTY);
4244a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DELETED, RawContacts.DELETED);
4254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.TIMES_CONTACTED, RawContacts.TIMES_CONTACTED);
4264a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.LAST_TIME_CONTACTED,
4274a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                RawContacts.LAST_TIME_CONTACTED);
4284a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.CUSTOM_RINGTONE, RawContacts.CUSTOM_RINGTONE);
4294a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SEND_TO_VOICEMAIL, RawContacts.SEND_TO_VOICEMAIL);
4304a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.STARRED, RawContacts.STARRED);
4314a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE);
4324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC1, RawContacts.SYNC1);
4334a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC2, RawContacts.SYNC2);
4344a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC3, RawContacts.SYNC3);
4354a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC4, RawContacts.SYNC4);
4362815f58f72f109790585931f601a63ddc02536a5Evan Millar
4374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap = new HashMap<String, String>();
4384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data._ID, Data._ID);
4394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.RAW_CONTACT_ID, Data.RAW_CONTACT_ID);
4404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA_VERSION, Data.DATA_VERSION);
4414a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.IS_PRIMARY, Data.IS_PRIMARY);
4424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY);
4434a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.RES_PACKAGE, Data.RES_PACKAGE);
4444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.MIMETYPE, Data.MIMETYPE);
4454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA1, Data.DATA1);
4464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA2, Data.DATA2);
4474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA3, Data.DATA3);
4484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA4, Data.DATA4);
4494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA5, Data.DATA5);
4504a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA6, Data.DATA6);
4514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA7, Data.DATA7);
4524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA8, Data.DATA8);
4534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA9, Data.DATA9);
4544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA10, Data.DATA10);
4554a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA11, Data.DATA11);
4564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA12, Data.DATA12);
4574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA13, Data.DATA13);
4584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA14, Data.DATA14);
4594a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA15, Data.DATA15);
4604a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC1, Data.SYNC1);
4614a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC2, Data.SYNC2);
4624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC3, Data.SYNC3);
4634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC4, Data.SYNC4);
4644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
4654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
4664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
4674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
4684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.VERSION, RawContacts.VERSION);
4694a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.DIRTY, RawContacts.DIRTY);
4704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME);
4714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
4724a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
4734a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
4744a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
4754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
4764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
4774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(GroupMembership.GROUP_SOURCE_ID, GroupMembership.GROUP_SOURCE_ID);
478a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
479e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap = new HashMap<String, String>();
480e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup._ID,
481e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_ID + " AS " + PhoneLookup._ID);
482e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.DISPLAY_NAME,
483e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_DISPLAY_NAME + " AS " + PhoneLookup.DISPLAY_NAME);
484e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.LAST_TIME_CONTACTED,
485e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_LAST_TIME_CONTACTED
486e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                        + " AS " + PhoneLookup.LAST_TIME_CONTACTED);
487e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.TIMES_CONTACTED,
488e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_TIMES_CONTACTED + " AS " + PhoneLookup.TIMES_CONTACTED);
489e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.STARRED,
490e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_STARRED + " AS " + PhoneLookup.STARRED);
491e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.IN_VISIBLE_GROUP,
492e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Contacts.IN_VISIBLE_GROUP + " AS " + PhoneLookup.IN_VISIBLE_GROUP);
493e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.PHOTO_ID,
494e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Contacts.PHOTO_ID + " AS " + PhoneLookup.PHOTO_ID);
495e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.CUSTOM_RINGTONE,
496e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_CUSTOM_RINGTONE + " AS " + PhoneLookup.CUSTOM_RINGTONE);
497e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.HAS_PHONE_NUMBER,
498e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Contacts.HAS_PHONE_NUMBER + " AS " + PhoneLookup.HAS_PHONE_NUMBER);
499e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.SEND_TO_VOICEMAIL,
500e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_SEND_TO_VOICEMAIL
501e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                        + " AS " + PhoneLookup.SEND_TO_VOICEMAIL);
502e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.NUMBER,
503e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.NUMBER + " AS " + PhoneLookup.NUMBER);
504e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.TYPE,
505e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.TYPE + " AS " + PhoneLookup.TYPE);
506e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.LABEL,
507e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.LABEL + " AS " + PhoneLookup.LABEL);
5089261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
509e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        HashMap<String, String> columns;
5107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
511ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Groups projection map
512ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
513ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups._ID, "groups._id AS _id");
514035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_NAME, Groups.ACCOUNT_NAME);
515035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_TYPE, Groups.ACCOUNT_TYPE);
5169261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.SOURCE_ID, Groups.SOURCE_ID);
5179261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.DIRTY, Groups.DIRTY);
5189261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.VERSION, Groups.VERSION);
51967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Groups.RES_PACKAGE, PackagesColumns.PACKAGE + " AS " + Groups.RES_PACKAGE);
520ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.TITLE, Groups.TITLE);
52167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Groups.TITLE_RES, Groups.TITLE_RES);
522ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.GROUP_VISIBLE, Groups.GROUP_VISIBLE);
5233cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYSTEM_ID, Groups.SYSTEM_ID);
52494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        columns.put(Groups.DELETED, Groups.DELETED);
5253cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.NOTES, Groups.NOTES);
52638446bf47c5ee2080df69f5fc8a33ad2fa3e61b5Jeff Sharkey        columns.put(Groups.SHOULD_SYNC, Groups.SHOULD_SYNC);
5273cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC1, Tables.GROUPS + "." + Groups.SYNC1 + " AS " + Groups.SYNC1);
5283cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC2, Tables.GROUPS + "." + Groups.SYNC2 + " AS " + Groups.SYNC2);
5293cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC3, Tables.GROUPS + "." + Groups.SYNC3 + " AS " + Groups.SYNC3);
5303cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC4, Tables.GROUPS + "." + Groups.SYNC4 + " AS " + Groups.SYNC4);
531ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsProjectionMap = columns;
532ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
5336cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        // RawContacts and groups projection map
534ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
535ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.putAll(sGroupsProjectionMap);
536d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Groups.SUMMARY_COUNT, "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID
537d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
538ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
539ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + ") AS " + Groups.SUMMARY_COUNT);
540ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.SUMMARY_WITH_PHONES, "(SELECT COUNT(DISTINCT "
541d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ContactsColumns.CONCRETE_ID + ") FROM "
542d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
543ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
544f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov                + " AND " + Contacts.HAS_PHONE_NUMBER + ") AS " + Groups.SUMMARY_WITH_PHONES);
545ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsSummaryProjectionMap = columns;
546ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
547b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        // Aggregate exception projection map
548b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns = new HashMap<String, String>();
549b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id AS _id");
550b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE);
551d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(AggregationExceptions.CONTACT_ID,
552d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                "raw_contacts1." + RawContacts.CONTACT_ID
553d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " AS " + AggregationExceptions.CONTACT_ID);
5545ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        columns.put(AggregationExceptions.RAW_CONTACT_ID, AggregationExceptionColumns.RAW_CONTACT_ID2);
555b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        sAggregationExceptionsProjectionMap = columns;
556b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
557eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        // Settings projection map
558eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns = new HashMap<String, String>();
559eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.ACCOUNT_NAME, Settings.ACCOUNT_NAME);
560eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.ACCOUNT_TYPE, Settings.ACCOUNT_TYPE);
561eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.UNGROUPED_VISIBLE, Settings.UNGROUPED_VISIBLE);
562eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.SHOULD_SYNC, Settings.SHOULD_SYNC);
56368936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey        columns.put(Settings.UNGROUPED_COUNT, "(SELECT COUNT(*) FROM (SELECT 1 FROM "
56468936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS + " GROUP BY "
56568936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID + " HAVING " + Clauses.HAVING_NO_GROUPS
56668936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + ")) AS " + Settings.UNGROUPED_COUNT);
56768936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey        columns.put(Settings.UNGROUPED_WITH_PHONES, "(SELECT COUNT(*) FROM (SELECT 1 FROM "
568e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS + " WHERE "
56968936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Contacts.HAS_PHONE_NUMBER + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID
57068936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + " HAVING " + Clauses.HAVING_NO_GROUPS + ")) AS "
57168936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Settings.UNGROUPED_WITH_PHONES);
572eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        sSettingsProjectionMap = columns;
573eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
574373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns = new HashMap<String, String>();
575373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence._ID, Presence._ID);
5764dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        columns.put(PresenceColumns.RAW_CONTACT_ID, PresenceColumns.RAW_CONTACT_ID);
577373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.DATA_ID, Presence.DATA_ID);
578373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.IM_ACCOUNT, Presence.IM_ACCOUNT);
579373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.IM_HANDLE, Presence.IM_HANDLE);
5804dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        columns.put(Presence.PROTOCOL, Presence.PROTOCOL);
5814dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        columns.put(Presence.CUSTOM_PROTOCOL, Presence.CUSTOM_PROTOCOL);
582373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.PRESENCE_STATUS, Presence.PRESENCE_STATUS);
583373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.PRESENCE_CUSTOM_STATUS, Presence.PRESENCE_CUSTOM_STATUS);
584373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        sPresenceProjectionMap = columns;
585373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov
586a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov        sDataWithPresenceProjectionMap = new HashMap<String, String>();
587a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov        sDataWithPresenceProjectionMap.putAll(sDataProjectionMap);
588a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov        sDataWithPresenceProjectionMap.put(Presence.PRESENCE_STATUS,
589e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                Presence.PRESENCE_STATUS);
590a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov        sDataWithPresenceProjectionMap.put(Presence.PRESENCE_CUSTOM_STATUS,
591e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                Presence.PRESENCE_CUSTOM_STATUS);
59219a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
5931b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // Live folder projection
5941b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap = new HashMap<String, String>();
5951b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap.put(LiveFolders._ID,
5961b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                Contacts._ID + " AS " + LiveFolders._ID);
5971b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap.put(LiveFolders.NAME,
5981b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                Contacts.DISPLAY_NAME + " AS " + LiveFolders.NAME);
5991b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
6001b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // TODO: Put contact photo back when we have a way to display a default icon
6011b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // for contacts without a photo
6021b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // sLiveFoldersProjectionMap.put(LiveFolders.ICON_BITMAP,
6031b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        //      Photos.DATA + " AS " + LiveFolders.ICON_BITMAP);
6041b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
6054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsInGroupSelect = Contacts._ID + " IN "
6064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                + "(SELECT " + RawContacts.CONTACT_ID
6074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                + " FROM " + Tables.RAW_CONTACTS
6084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN "
6094a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID
6104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        + " FROM " + Tables.DATA_JOIN_MIMETYPES
6114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE
6124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + "' AND " + GroupMembership.GROUP_ROW_ID + "="
6134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + "(SELECT " + Tables.GROUPS + "." + Groups._ID
6144a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + " FROM " + Tables.GROUPS
6154a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + " WHERE " + Groups.TITLE + "=?)))";
6164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
6174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
6183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /**
6193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     * Handles inserts and update for a specific Data type.
6203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     */
6213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private abstract class DataRowHandler {
6223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected final String mMimetype;
624653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        protected long mMimetypeId;
6253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public DataRowHandler(String mimetype) {
6273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mMimetype = mimetype;
6283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
630653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        protected long getMimeTypeId() {
631653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (mMimetypeId == 0) {
632653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                mMimetypeId = mOpenHelper.getMimeTypeId(mMimetype);
633653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
634653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return mMimetypeId;
635653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
636653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
6373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
6383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Inserts a row into the {@link Data} table.
6393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
6405ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
641e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            final long dataId = db.insert(Tables.DATA, null, values);
642e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
643e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            Integer primary = values.getAsInteger(Data.IS_PRIMARY);
644e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (primary != null && primary != 0) {
645653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, getMimeTypeId());
646e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
647e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
648e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return dataId;
6493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
6523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Validates data and updates a {@link Data} row using the cursor, which contains
6533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * the current data.
6543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
655653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
656653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                boolean markRawContactAsDirty) {
65714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
65814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
659653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
660653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (values.containsKey(Data.IS_SUPER_PRIMARY)) {
661653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                long mimeTypeId = getMimeTypeId();
662653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
663653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, mimeTypeId);
664653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
665653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                // Now that we've taken care of setting these, remove them from "values".
666653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_SUPER_PRIMARY);
667653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_PRIMARY);
668653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            } else if (values.containsKey(Data.IS_PRIMARY)) {
669653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, getMimeTypeId());
670653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
671653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                // Now that we've taken care of setting this, remove it from "values".
672653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_PRIMARY);
673653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
674653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
675653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (values.size() > 0) {
676653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                mDb.update(Tables.DATA, values, Data._ID + " = " + dataId, null);
677653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
678653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
679653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (markRawContactAsDirty) {
680653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setRawContactDirty(rawContactId);
681653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
6823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
68514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
68614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
68714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            boolean primary = c.getInt(DataDeleteQuery.IS_PRIMARY) != 0;
6883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            int count = db.delete(Tables.DATA, Data._ID + "=" + dataId, null);
6893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (count != 0 && primary) {
6905ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                fixPrimary(db, rawContactId);
6913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
6923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return count;
6933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6955ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        private void fixPrimary(SQLiteDatabase db, long rawContactId) {
6965ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long newPrimaryId = findNewPrimaryDataId(db, rawContactId);
6973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (newPrimaryId != -1) {
69814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                setIsPrimary(rawContactId, newPrimaryId, getMimeTypeId());
6993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
7003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7025ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected long findNewPrimaryDataId(SQLiteDatabase db, long rawContactId) {
703e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            long primaryId = -1;
704e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            int primaryType = -1;
7055ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Cursor c = queryData(db, rawContactId);
7063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
707e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                while (c.moveToNext()) {
70814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    long dataId = c.getLong(DataDeleteQuery._ID);
70914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    int type = c.getInt(DataDeleteQuery.DATA2);
710e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) {
711e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryId = dataId;
712e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryType = type;
713e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    }
7143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
7153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
7163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
7173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
718e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return primaryId;
719e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
720e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
721e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        /**
722e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * Returns the rank of a specific record type to be used in determining the primary
723e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * row. Lower number represents higher priority.
724e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         */
725e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
726e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return 0;
7273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7295ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected Cursor queryData(SQLiteDatabase db, long rawContactId) {
73014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return db.query(DataDeleteQuery.TABLE, DataDeleteQuery.CONCRETE_COLUMNS,
73114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    Data.RAW_CONTACT_ID + "=" + rawContactId +
73214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    " AND " + MimetypesColumns.MIMETYPE + "='" + mMimetype + "'",
7333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    null, null, null, null);
7343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7365ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected void fixContactDisplayName(SQLiteDatabase db, long rawContactId) {
7373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String bestDisplayName = null;
73867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            Cursor c = db.query(DisplayNameQuery.TABLE, DisplayNameQuery.COLUMNS,
7395ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    Data.RAW_CONTACT_ID + "=" + rawContactId, null, null, null, null);
7403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
7413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                int maxPriority = -1;
7423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                while (c.moveToNext()) {
7433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    String mimeType = c.getString(DisplayNameQuery.MIMETYPE);
7443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    boolean primary;
7453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    String name;
7463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
7483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        name = c.getString(DisplayNameQuery.DISPLAY_NAME);
7493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        primary = true;
7503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    } else {
7513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        name = c.getString(DisplayNameQuery.DATA2);
7523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        primary = (c.getInt(DisplayNameQuery.IS_PRIMARY) != 0);
7533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    }
7543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    if (primary && name != null) {
7563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        Integer priority = sDisplayNamePriorities.get(mimeType);
7573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        if (priority != null && priority > maxPriority) {
7583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                            maxPriority = priority;
7593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                            bestDisplayName = name;
7603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        }
7613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    }
7623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
7633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
7653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
7663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
7673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
768653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            setDisplayName(rawContactId, bestDisplayName);
76914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
77014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            // TODO also fix the aggregate contact display name right away
7713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
772a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
773a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
774a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return true;
775a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
7763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
7773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CustomDataRowHandler extends DataRowHandler {
7793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CustomDataRowHandler(String mimetype) {
7813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
7823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
7843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class StructuredNameRowHandler extends DataRowHandler {
7863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final NameSplitter mNameSplitter;
7883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public StructuredNameRowHandler(NameSplitter nameSplitter) {
7903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(StructuredName.CONTENT_ITEM_TYPE);
7913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mNameSplitter = nameSplitter;
7923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
7955ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
7963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            fixStructuredNameComponents(values);
79714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
79814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
79914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
80014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String givenName = values.getAsString(StructuredName.GIVEN_NAME);
80114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String familyName = values.getAsString(StructuredName.FAMILY_NAME);
80214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.insertNameLookupForStructuredName(rawContactId, dataId, givenName,
80314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    familyName);
80414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            fixContactDisplayName(db, rawContactId);
80514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
80614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
80714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
80814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
80914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
81014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                boolean markRawContactAsDirty) {
811cabac02a2416b495e030654accffcbb5ae526678Dmitri Plotnikov
812cabac02a2416b495e030654accffcbb5ae526678Dmitri Plotnikov            fixStructuredNameComponents(values);
813cabac02a2416b495e030654accffcbb5ae526678Dmitri Plotnikov
81414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
81514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
81614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
81714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super.update(db, values, c, markRawContactAsDirty);
81814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
81914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            boolean hasGivenName = values.containsKey(StructuredName.GIVEN_NAME);
82014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            boolean hasFamilyName = values.containsKey(StructuredName.FAMILY_NAME);
82114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            if  (hasGivenName || hasFamilyName) {
82214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                String givenName;
82314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                String familyName;// = values.getAsString(StructuredName.FAMILY_NAME);
82414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                if (hasGivenName) {
82514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    givenName = values.getAsString(StructuredName.GIVEN_NAME);
82614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                } else {
82714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
82814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    // TODO compiled statement
82914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    givenName = DatabaseUtils.stringForQuery(db,
83014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            "SELECT " + StructuredName.GIVEN_NAME +
83114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            " FROM " + Tables.DATA +
83214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            " WHERE " + Data._ID + "=" + dataId, null);
83314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                }
83414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                if (hasFamilyName) {
83514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    familyName = values.getAsString(StructuredName.FAMILY_NAME);
83614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                } else {
83714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
83814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    // TODO compiled statement
83914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    familyName = DatabaseUtils.stringForQuery(db,
84014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            "SELECT " + StructuredName.FAMILY_NAME +
84114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            " FROM " + Tables.DATA +
84214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            " WHERE " + Data._ID + "=" + dataId, null);
84314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                }
84414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
84514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                mOpenHelper.deleteNameLookup(dataId);
84614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                mOpenHelper.insertNameLookupForStructuredName(rawContactId, dataId, givenName,
84714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                        familyName);
84814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            }
84914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            fixContactDisplayName(db, rawContactId);
85014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
85114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
85214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
85314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
85414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
85514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
85614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
85714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
85814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
85914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.deleteNameLookup(dataId);
86014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            fixContactDisplayName(db, rawContactId);
86114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
8623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
8653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Parses the supplied display name, but only if the incoming values do not already contain
8663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * structured name parts.  Also, if the display name is not provided, generate one by
8673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * concatenating first name and last name
8683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         *
8693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * TODO see if the order of first and last names needs to be conditionally reversed for
8703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * some locales, e.g. China.
8713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
8723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private void fixStructuredNameComponents(ContentValues values) {
8733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String fullName = values.getAsString(StructuredName.DISPLAY_NAME);
8743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (!TextUtils.isEmpty(fullName)
8753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.PREFIX))
8763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.GIVEN_NAME))
8773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.MIDDLE_NAME))
8783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.FAMILY_NAME))
8793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.SUFFIX))) {
8803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                NameSplitter.Name name = new NameSplitter.Name();
8813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                mNameSplitter.split(name, fullName);
8823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.PREFIX, name.getPrefix());
8843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.GIVEN_NAME, name.getGivenNames());
8853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.MIDDLE_NAME, name.getMiddleName());
8863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.FAMILY_NAME, name.getFamilyName());
8873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.SUFFIX, name.getSuffix());
8883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (TextUtils.isEmpty(fullName)) {
8913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                String givenName = values.getAsString(StructuredName.GIVEN_NAME);
8923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                String familyName = values.getAsString(StructuredName.FAMILY_NAME);
8933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                if (TextUtils.isEmpty(givenName)) {
8943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = familyName;
8953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                } else if (TextUtils.isEmpty(familyName)) {
8963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = givenName;
8973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                } else {
8983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = givenName + " " + familyName;
8993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
9003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                if (!TextUtils.isEmpty(fullName)) {
9023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    values.put(StructuredName.DISPLAY_NAME, fullName);
9033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
9043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
9073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CommonDataRowHandler extends DataRowHandler {
9093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mTypeColumn;
9113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mLabelColumn;
9123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CommonDataRowHandler(String mimetype, String typeColumn, String labelColumn) {
9143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
9153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mTypeColumn = typeColumn;
9163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mLabelColumn = labelColumn;
9173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
9205ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
9213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            int type;
9223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String label;
9233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (values.containsKey(mTypeColumn)) {
9243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                type = values.getAsInteger(mTypeColumn);
9253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } else {
9263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                type = BaseTypes.TYPE_CUSTOM;
9273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (values.containsKey(mLabelColumn)) {
9293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                label = values.getAsString(mLabelColumn);
9303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } else {
9313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                label = null;
9323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (type != BaseTypes.TYPE_CUSTOM && label != null) {
9357a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException(mLabelColumn + " value can only be specified with "
9363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        + mTypeColumn + "=" + BaseTypes.TYPE_CUSTOM + "(custom)");
9373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (type == BaseTypes.TYPE_CUSTOM && label == null) {
9407a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException(mLabelColumn + " value must be specified when "
9413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        + mTypeColumn + "=" + BaseTypes.TYPE_CUSTOM + "(custom)");
9423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return super.insert(db, rawContactId, values);
9453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
9473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class OrganizationDataRowHandler extends CommonDataRowHandler {
9493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public OrganizationDataRowHandler() {
9513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Organization.CONTENT_ITEM_TYPE, Organization.TYPE, Organization.LABEL);
9523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
9555ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
9565ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long id = super.insert(db, rawContactId, values);
9575ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            fixContactDisplayName(db, rawContactId);
9583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return id;
9593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
96214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
96314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                boolean markRawContactAsDirty) {
96414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
96514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
96614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super.update(db, values, c, markRawContactAsDirty);
96714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
96814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            fixContactDisplayName(db, rawContactId);
96914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
97014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
97114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
97214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
97314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
97414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
97514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
97614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            fixContactDisplayName(db, rawContactId);
97714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
97814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
97914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
98014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
9813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
9823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
9833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_WORK: return 0;
9843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_CUSTOM: return 1;
9853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_OTHER: return 2;
9863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
9873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
989a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
990a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
991a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
992a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return false;
993a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
9943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
9953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
996e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    public class EmailDataRowHandler extends CommonDataRowHandler {
997e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
998e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public EmailDataRowHandler() {
999e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            super(Email.CONTENT_ITEM_TYPE, Email.TYPE, Email.LABEL);
1000e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1001e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1002e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
10035ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
100414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String address = values.getAsString(Email.DATA);
100514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
100614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
100714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
10085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            fixContactDisplayName(db, rawContactId);
100914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.insertNameLookupForEmail(rawContactId, dataId, address);
101014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
101114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
101214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
101314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
101414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
101514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                boolean markRawContactAsDirty) {
101614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
101714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
101814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String address = values.getAsString(Email.DATA);
101914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
102014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super.update(db, values, c, markRawContactAsDirty);
102114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
102214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.deleteNameLookup(dataId);
102314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.insertNameLookupForEmail(rawContactId, dataId, address);
102414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            fixContactDisplayName(db, rawContactId);
102514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
102614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
102714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
102814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
102914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
103014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
103114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
103214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
103314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
103414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.deleteNameLookup(dataId);
103514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            fixContactDisplayName(db, rawContactId);
103614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
1037e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1038e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1039e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
1040e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
1041e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            switch (type) {
1042e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_HOME: return 0;
1043e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_WORK: return 1;
1044e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_CUSTOM: return 2;
1045e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_OTHER: return 3;
1046e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                default: return 1000;
1047e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
1048e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1049e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    }
1050e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
105114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    public class NicknameDataRowHandler extends CommonDataRowHandler {
105214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
105314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public NicknameDataRowHandler() {
105414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super(Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE, Nickname.LABEL);
105514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
105614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
105714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
105814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
105914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String nickname = values.getAsString(Nickname.NAME);
106014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
106114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
106214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
106314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            fixContactDisplayName(db, rawContactId);
106414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.insertNameLookupForNickname(rawContactId, dataId, nickname);
106514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
106614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
106714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
106814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
106914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
107014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                boolean markRawContactAsDirty) {
107114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
107214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
107314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String nickname = values.getAsString(Nickname.NAME);
107414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
107514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super.update(db, values, c, markRawContactAsDirty);
107614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
107714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.deleteNameLookup(dataId);
107814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.insertNameLookupForNickname(rawContactId, dataId, nickname);
107914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            fixContactDisplayName(db, rawContactId);
108014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
108114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
108214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
108314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
108414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
108514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
108614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
108714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
108814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
108914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.deleteNameLookup(dataId);
109014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            fixContactDisplayName(db, rawContactId);
109114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
109214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
109314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    }
109414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
10953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class PhoneDataRowHandler extends CommonDataRowHandler {
10963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public PhoneDataRowHandler() {
10983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Phone.CONTENT_ITEM_TYPE, Phone.TYPE, Phone.LABEL);
10993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
11003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
11025ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
11030b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            long dataId;
11040b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            if (values.containsKey(Phone.NUMBER)) {
11050b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String number = values.getAsString(Phone.NUMBER);
11060b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String normalizedNumber = computeNormalizedNumber(number, values);
1107653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
11080b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                dataId = super.insert(db, rawContactId, values);
1109653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
11100b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
11110b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                fixContactDisplayName(db, rawContactId);
11120b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            } else {
11130b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                dataId = super.insert(db, rawContactId, values);
11140b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            }
1115653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return dataId;
1116653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1117653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1118653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1119653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1120653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                boolean markRawContactAsDirty) {
112114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
112214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
11230b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            if (values.containsKey(Phone.NUMBER)) {
11240b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String number = values.getAsString(Phone.NUMBER);
11250b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String normalizedNumber = computeNormalizedNumber(number, values);
1126653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
11270b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                super.update(db, values, c, markRawContactAsDirty);
1128653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
11290b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
11300b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                fixContactDisplayName(db, rawContactId);
11310b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            } else {
11320b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                super.update(db, values, c, markRawContactAsDirty);
11330b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            }
113414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
113514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
113614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
113714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
113814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
113914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
114014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
114114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
114214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
114314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            updatePhoneLookup(db, rawContactId, dataId, null, null);
114414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            fixContactDisplayName(db, rawContactId);
114514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
1146653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1147653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1148653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        private String computeNormalizedNumber(String number, ContentValues values) {
1149e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            String normalizedNumber = null;
1150e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (number != null) {
1151e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                normalizedNumber = PhoneNumberUtils.getStrippedReversed(number);
1152e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
1153653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            values.put(PhoneColumns.NORMALIZED_NUMBER, normalizedNumber);
1154653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return normalizedNumber;
1155653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1156e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1157653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        private void updatePhoneLookup(SQLiteDatabase db, long rawContactId, long dataId,
1158653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                String number, String normalizedNumber) {
1159e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (number != null) {
1160653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                ContentValues phoneValues = new ContentValues();
11615ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.RAW_CONTACT_ID, rawContactId);
1162653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.DATA_ID, dataId);
1163e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, normalizedNumber);
1164653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                db.replace(Tables.PHONE_LOOKUP, null, phoneValues);
1165653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            } else {
1166653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                db.delete(Tables.PHONE_LOOKUP, PhoneLookupColumns.DATA_ID + "=" + dataId, null);
1167e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
11683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
11693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
11713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
11723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
11733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_MOBILE: return 0;
11743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_WORK: return 1;
11753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_HOME: return 2;
11763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_PAGER: return 3;
11773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_CUSTOM: return 4;
11783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_OTHER: return 5;
11793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_WORK: return 6;
11803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_HOME: return 7;
11813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
11823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
11833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
11843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
11853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1186653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    public class GroupMembershipRowHandler extends DataRowHandler {
1187653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1188653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public GroupMembershipRowHandler() {
1189653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            super(GroupMembership.CONTENT_ITEM_TYPE);
1190653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1191653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1192653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1193653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1194653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            resolveGroupSourceIdInValues(rawContactId, db, values, true);
1195653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return super.insert(db, rawContactId, values);
1196653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1197653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1198653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1199653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1200653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                boolean markRawContactAsDirty) {
120114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1202653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            resolveGroupSourceIdInValues(rawContactId, db, values, false);
1203653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            super.update(db, values, c, markRawContactAsDirty);
1204653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1205653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1206653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        private void resolveGroupSourceIdInValues(long rawContactId, SQLiteDatabase db,
1207653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                ContentValues values, boolean isInsert) {
1208653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            boolean containsGroupSourceId = values.containsKey(GroupMembership.GROUP_SOURCE_ID);
1209653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            boolean containsGroupId = values.containsKey(GroupMembership.GROUP_ROW_ID);
1210653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (containsGroupSourceId && containsGroupId) {
1211653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                throw new IllegalArgumentException(
1212653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        "you are not allowed to set both the GroupMembership.GROUP_SOURCE_ID "
1213653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                + "and GroupMembership.GROUP_ROW_ID");
1214653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1215653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1216653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (!containsGroupSourceId && !containsGroupId) {
1217653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                if (isInsert) {
1218653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                    throw new IllegalArgumentException(
1219653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                            "you must set exactly one of GroupMembership.GROUP_SOURCE_ID "
1220653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                    + "and GroupMembership.GROUP_ROW_ID");
1221653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                } else {
1222653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                    return;
1223653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                }
1224653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1225653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1226653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (containsGroupSourceId) {
1227653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                final String sourceId = values.getAsString(GroupMembership.GROUP_SOURCE_ID);
1228653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                final long groupId = getOrMakeGroup(db, rawContactId, sourceId);
1229653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(GroupMembership.GROUP_SOURCE_ID);
1230653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.put(GroupMembership.GROUP_ROW_ID, groupId);
1231653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1232653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1233a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1234a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1235a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
1236a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return false;
1237a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1238653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    }
1239653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1240a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov    public class PhotoDataRowHandler extends DataRowHandler {
1241a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1242a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public PhotoDataRowHandler() {
1243a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            super(Photo.CONTENT_ITEM_TYPE);
1244a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1245a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1246a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1247a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
1248a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
1249a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            triggerAggregation(rawContactId);
1250a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return dataId;
1251a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1252a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1253a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1254a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1255a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                boolean markRawContactAsDirty) {
1256a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1257a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            super.update(db, values, c, markRawContactAsDirty);
1258a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            mContactAggregator.updatePhotoId(db, rawContactId);
1259a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1260a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1261a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1262a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
1263a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
1264a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            int count = super.delete(db, c);
1265a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            mContactAggregator.updatePhotoId(db, rawContactId);
1266a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return count;
1267a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1268a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1269a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1270a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
1271a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return false;
1272a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1273a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov    }
1274a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1275a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
12763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private HashMap<String, DataRowHandler> mDataRowHandlers;
127753056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov    private final ContactAggregationScheduler mAggregationScheduler;
12784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    private OpenHelper mOpenHelper;
127931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
1280a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    private ContactAggregator mContactAggregator;
12814097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov    private NameSplitter mNameSplitter;
1282f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private LegacyApiSupport mLegacyApiSupport;
1283a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    private GlobalSearchSupport mGlobalSearchSupport;
1284a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
128520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private ContentValues mValues = new ContentValues();
128620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1287ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov    private volatile CountDownLatch mAccessLatch;
128873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private boolean mImportMode;
128973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1290de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    private boolean mScheduleAggregation;
1291de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov
1292a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    public ContactsProvider2() {
129353056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        this(new ContactAggregationScheduler());
1294a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1295a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1296a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
1297a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Constructor for testing.
1298a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
129953056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov    /* package */ ContactsProvider2(ContactAggregationScheduler scheduler) {
130053056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        mAggregationScheduler = scheduler;
1301a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
13024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
13034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
13044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public boolean onCreate() {
1305de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        super.onCreate();
130635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1307de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final Context context = getContext();
1308de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mOpenHelper = (OpenHelper)getOpenHelper();
1309a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mGlobalSearchSupport = new GlobalSearchSupport(this);
1310a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mLegacyApiSupport = new LegacyApiSupport(context, mOpenHelper, this, mGlobalSearchSupport);
1311cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov        mContactAggregator = new ContactAggregator(this, mOpenHelper, mAggregationScheduler);
1312a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1313d51a83ac4f8032b62d9a23b90a8f43d6b7eb2dbbDmitri Plotnikov        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1314653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1315c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement = db.compileStatement(
1316653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "UPDATE " + Tables.DATA +
1317653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " SET " + Data.IS_PRIMARY + "=(_id=?)" +
1318653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " WHERE " + DataColumns.MIMETYPE_ID + "=?" +
1319653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "   AND " + Data.RAW_CONTACT_ID + "=?");
1320653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1321c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement = db.compileStatement(
1322653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "UPDATE " + Tables.DATA +
1323653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " SET " + Data.IS_SUPER_PRIMARY + "=(" + Data._ID + "=?)" +
1324653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " WHERE " + DataColumns.MIMETYPE_ID + "=?" +
1325653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "   AND " + Data.RAW_CONTACT_ID + " IN (" +
1326653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        "SELECT " + RawContacts._ID +
1327653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        " FROM " + Tables.RAW_CONTACTS +
1328653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        " WHERE " + RawContacts.CONTACT_ID + " =(" +
1329653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                "SELECT " + RawContacts.CONTACT_ID +
1330653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                " FROM " + Tables.RAW_CONTACTS +
1331653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                " WHERE " + RawContacts._ID + "=?))");
1332653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
13335ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mLastTimeContactedUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
13346cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                + RawContacts.TIMES_CONTACTED + "=" + RawContacts.TIMES_CONTACTED + "+1,"
1335d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + RawContacts.LAST_TIME_CONTACTED + "=? WHERE " + RawContacts.CONTACT_ID + "=?");
1336a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
13375ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mContactDisplayNameUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
13386cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                + RawContactsColumns.DISPLAY_NAME + "=? WHERE " + RawContacts._ID + "=?");
13393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
134073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
134173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                + RawContacts.DIRTY + "=1 WHERE " + RawContacts._ID + "=?");
134273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1343e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        mAggregatedPresenceReplace = db.compileStatement(
1344e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                "INSERT OR REPLACE INTO " + Tables.AGGREGATED_PRESENCE + "("
1345e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + AggregatedPresenceColumns.CONTACT_ID + ", "
1346e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + Presence.PRESENCE_STATUS
1347e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                + ") VALUES (?, (SELECT MAX(" + Presence.PRESENCE_STATUS + ")"
1348e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + " FROM " + Tables.PRESENCE + "," + Tables.RAW_CONTACTS
1349a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                        + " WHERE " + PresenceColumns.RAW_CONTACT_ID + "="
1350e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                                + RawContactsColumns.CONCRETE_ID
1351e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + "   AND " + RawContacts.CONTACT_ID + "=?))");
1352e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
1353e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        mAggregatedPresenceStatusUpdate = db.compileStatement(
1354e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                "UPDATE " + Tables.AGGREGATED_PRESENCE
1355e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                + " SET " + Presence.PRESENCE_CUSTOM_STATUS + "=? "
1356e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                + " WHERE " + AggregatedPresenceColumns.CONTACT_ID + "=?");
1357e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
135828f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar        mNameSplitter = new NameSplitter(
135928f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_prefixes),
136028f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_last_name_prefixes),
136128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_suffixes),
136228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_conjunctions));
13634097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
13643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers = new HashMap<String, DataRowHandler>();
13653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1366e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, new EmailDataRowHandler());
13673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE,
13683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new CommonDataRowHandler(Im.CONTENT_ITEM_TYPE, Im.TYPE, Im.LABEL));
136967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler(
137067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, StructuredPostal.LABEL));
13713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, new OrganizationDataRowHandler());
13723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, new PhoneDataRowHandler());
137314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new NicknameDataRowHandler());
13743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE,
13753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new StructuredNameRowHandler(mNameSplitter));
1376a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        mDataRowHandlers.put(GroupMembership.CONTENT_ITEM_TYPE, new GroupMembershipRowHandler());
1377a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        mDataRowHandlers.put(Photo.CONTENT_ITEM_TYPE, new PhotoDataRowHandler());
13783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
13793d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        if (isLegacyContactImportNeeded()) {
1380568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            importLegacyContactsAsync();
13813d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
1382568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
13831f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        return (db != null);
13844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
13854f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
138631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    /* Visible for testing */
1387de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    @Override
138831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    protected OpenHelper getOpenHelper(final Context context) {
138931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov        return OpenHelper.getInstance(context);
139031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    }
139131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
1392013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    /* package */ NameSplitter getNameSplitter() {
1393013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov        return mNameSplitter;
1394013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    }
1395013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov
13963d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    protected boolean isLegacyContactImportNeeded() {
13973d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
13983d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        return prefs.getInt(PREF_CONTACTS_IMPORTED, 0) < PREF_CONTACTS_IMPORT_VERSION;
13993d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
14003d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1401568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    protected LegacyContactImporter getLegacyContactImporter() {
1402568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return new LegacyContactImporter(getContext(), this);
1403568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1404568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1405568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /**
1406568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * Imports legacy contacts in a separate thread.  As long as the import process is running
1407568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * all other access to the contacts is blocked.
1408568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     */
1409568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    private void importLegacyContactsAsync() {
1410ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        mAccessLatch = new CountDownLatch(1);
1411568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1412568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        Thread importThread = new Thread("LegacyContactImport") {
1413568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            @Override
1414568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            public void run() {
1415568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                if (importLegacyContacts()) {
1416568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1417568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                    /*
1418568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     * When the import process is done, we can unlock the provider and
1419568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     * start aggregating the imported contacts asynchronously.
1420568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     */
1421ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch.countDown();
1422ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch = null;
1423568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                    scheduleContactAggregation();
1424568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                }
1425568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            }
1426568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        };
1427568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1428568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        importThread.start();
1429568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1430568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
14313d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private boolean importLegacyContacts() {
1432568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        LegacyContactImporter importer = getLegacyContactImporter();
1433568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        if (importLegacyContacts(importer)) {
14343d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
14353d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            Editor editor = prefs.edit();
14363d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            editor.putInt(PREF_CONTACTS_IMPORTED, PREF_CONTACTS_IMPORT_VERSION);
14373d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            editor.commit();
14383d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return true;
14393d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        } else {
14403d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return false;
14413d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
14423d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
14433d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
14443d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /* Visible for testing */
1445568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /* package */ boolean importLegacyContacts(LegacyContactImporter importer) {
14463d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        mContactAggregator.setEnabled(false);
144773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mImportMode = true;
14483d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        try {
14493d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            importer.importContacts();
14503d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            mContactAggregator.setEnabled(true);
14513d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return true;
14523d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        } catch (Throwable e) {
14533d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov           Log.e(TAG, "Legacy contact import failed", e);
14543d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov           return false;
145573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        } finally {
145673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            mImportMode = false;
14573d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
14583d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
14593d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1460a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    @Override
1461a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    protected void finalize() throws Throwable {
1462a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        if (mContactAggregator != null) {
1463a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov            mContactAggregator.quit();
1464a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        }
1465a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1466a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        super.finalize();
1467a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1468a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1469a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
1470a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Wipes all data from the contacts database.
1471a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
1472a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /* package */ void wipeData() {
1473a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        mOpenHelper.wipeData();
1474a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1475a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1476568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /**
1477568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * While importing and aggregating contacts, this content provider will
1478568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * block all attempts to change contacts data. In particular, it will hold
1479568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * up all contact syncs. As soon as the import process is complete, all
1480568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * processes waiting to write to the provider are unblocked and can proceed
1481568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * to compete for the database transaction monitor.
1482568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     */
1483568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    private void waitForAccess() {
1484ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        CountDownLatch latch = mAccessLatch;
1485ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        if (latch != null) {
1486ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov            while (true) {
1487ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                try {
1488ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    latch.await();
1489ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch = null;
1490ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    return;
1491ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                } catch (InterruptedException e) {
1492ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                }
1493ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov            }
1494568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        }
1495568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1496568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1497568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1498568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public Uri insert(Uri uri, ContentValues values) {
1499568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1500568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.insert(uri, values);
1501568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1502568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1503568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1504568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
1505568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1506568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.update(uri, values, selection, selectionArgs);
1507568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1508568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1509568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1510568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public int delete(Uri uri, String selection, String[] selectionArgs) {
1511568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1512568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.delete(uri, selection, selectionArgs);
1513568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1514568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1515568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1516568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
1517568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            throws OperationApplicationException {
1518568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1519568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.applyBatch(operations);
1520568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1521568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
15224f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
1523de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected void onTransactionComplete() {
1524de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (mScheduleAggregation) {
1525de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            mScheduleAggregation = false;
1526568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            scheduleContactAggregation();
1527de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
1528de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        super.onTransactionComplete();
15294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
15304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1531cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    @Override
1532cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    protected void notifyChange() {
1533cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov        getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null);
1534cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    }
1535568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1536568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    protected void scheduleContactAggregation() {
1537568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        mContactAggregator.schedule();
1538568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1539568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
15403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private DataRowHandler getDataRowHandler(final String mimeType) {
15413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        DataRowHandler handler = mDataRowHandlers.get(mimeType);
15423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (handler == null) {
15433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            handler = new CustomDataRowHandler(mimeType);
15443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mDataRowHandlers.put(mimeType, handler);
15453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
15463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        return handler;
15473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
15483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
15494f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
1550de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected Uri insertInTransaction(Uri uri, ContentValues values) {
1551a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
1552a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
155335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1554a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        switch (match) {
155535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
1556de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                id = mOpenHelper.getSyncState().insert(mDb, values);
155735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                break;
155835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1559d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
1560d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                insertContact(values);
15616bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
15626bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
15636bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
15645ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
1565f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                final Account account = readAccountFromQueryParams(uri);
1566d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                id = insertRawContact(values, account);
1567a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1568a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1569a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
15705ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
15715ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1));
157273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                id = insertData(values, shouldMarkRawContactAsDirty(uri));
1573a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1574a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1575a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1576a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case DATA: {
157773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                id = insertData(values, shouldMarkRawContactAsDirty(uri));
1578a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1579a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1580a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1581ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
1582ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                final Account account = readAccountFromQueryParams(uri);
158373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                id = insertGroup(values, account, shouldMarkGroupAsDirty(uri));
1584ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
1585ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1586ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1587eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
1588e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                id = insertSettings(values);
1589eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
1590eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
1591eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
15921f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            case PRESENCE: {
15931f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                id = insertPresence(values);
15941f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                break;
15951f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
15961f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
1597a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            default:
1598f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.insert(uri, values);
1599a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
1600a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
16017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        if (id < 0) {
16027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return null;
16037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
16047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
1605de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return ContentUris.withAppendedId(uri, id);
1606a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
1607a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1608a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
1609035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * If account is non-null then store it in the values. If the account is already
1610035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * specified in the values then it must be consistent with the account, if it is non-null.
1611035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @param values the ContentValues to read from and update
1612035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @param account the explicitly provided Account
1613035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @return false if the accounts are inconsistent
16147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
1615035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana    private boolean resolveAccount(ContentValues values, Account account) {
1616035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        // If either is specified then both must be specified.
16176cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
16186cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
1619035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        if (!TextUtils.isEmpty(accountName) || !TextUtils.isEmpty(accountType)) {
1620035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            final Account valuesAccount = new Account(accountName, accountType);
1621035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            if (account != null && !valuesAccount.equals(account)) {
1622035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                return false;
1623035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            }
1624035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            account = valuesAccount;
1625035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
1626035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        if (account != null) {
1627df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana            values.put(RawContacts.ACCOUNT_NAME, account.name);
1628df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana            values.put(RawContacts.ACCOUNT_TYPE, account.type);
1629035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
1630035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        return true;
16317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
16327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
16337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
1634d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov     * Inserts an item in the contacts table
16356bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     *
16366bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @param values the values for the new row
16376bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @return the row ID of the newly created row
16386bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     */
1639d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertContact(ContentValues values) {
1640de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        throw new UnsupportedOperationException("Aggregate contacts are created automatically");
16416bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    }
16426bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
16436bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    /**
1644a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the contacts table
1645a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
1646a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
1647f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana     * @param account the account this contact should be associated with. may be null.
1648a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
1649a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
1650d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertRawContact(ContentValues values, Account account) {
16516bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov        /*
16526bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         * The contact record is inserted in the contacts table, but it needs to
16536bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         * be processed by the aggregator before it will be returned by the
16546bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         * "aggregates" queries.
16556bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         */
1656a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        ContentValues overriddenValues = new ContentValues(values);
1657d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        overriddenValues.putNull(RawContacts.CONTACT_ID);
1658f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        if (!resolveAccount(overriddenValues, account)) {
16597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return -1;
16607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
16617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
16623d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        if (values.containsKey(RawContacts.DELETED)
16633d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov                && values.getAsInteger(RawContacts.DELETED) != 0) {
16643d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            overriddenValues.put(RawContacts.AGGREGATION_MODE,
16653d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov                    RawContacts.AGGREGATION_MODE_DISABLED);
16663d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
16673d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1668023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        long rawContactId =
1669023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov                mDb.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, overriddenValues);
1670023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        mContactAggregator.markNewForAggregation(rawContactId);
1671023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        return rawContactId;
1672a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
1673a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1674a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
1675a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the data table
1676a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
1677a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
1678a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
1679a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
168073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private long insertData(ContentValues values, boolean markRawContactAsDirty) {
1681a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
1682de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.clear();
1683de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.putAll(values);
168467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
1685de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID);
168620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1687de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace package with internal mapping
1688de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String packageName = mValues.getAsString(Data.RES_PACKAGE);
1689de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (packageName != null) {
1690de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
1691de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
1692de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.RES_PACKAGE);
1693508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
1694de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace mimetype with internal mapping
1695de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String mimeType = mValues.getAsString(Data.MIMETYPE);
1696de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (TextUtils.isEmpty(mimeType)) {
1697de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            throw new IllegalArgumentException(Data.MIMETYPE + " is required");
1698de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
16994097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
1700de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.put(DataColumns.MIMETYPE_ID, mOpenHelper.getMimeTypeId(mimeType));
1701de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
1702a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1703a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        DataRowHandler rowHandler = getDataRowHandler(mimeType);
1704a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        id = rowHandler.insert(mDb, rawContactId, mValues);
1705de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (markRawContactAsDirty) {
1706de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            setRawContactDirty(rawContactId);
1707a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
1708a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1709a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        if (rowHandler.isAggregationRequired()) {
1710a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            triggerAggregation(rawContactId);
1711a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1712a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        return id;
17134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
17144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
17158e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov    private void triggerAggregation(long rawContactId) {
17168e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        if (!mContactAggregator.isEnabled()) {
17178e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            return;
17188e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        }
17198e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
17208e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        int aggregationMode = mOpenHelper.getAggregationMode(rawContactId);
1721f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        switch (aggregationMode) {
17228e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DISABLED:
17238e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                break;
17248e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
17258e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DEFAULT: {
1726421782cb554e5050cf62a86b98df6520038dcd15Dmitri Plotnikov                mContactAggregator.markForAggregation(rawContactId);
1727de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                mScheduleAggregation = true;
1728f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
17298e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
17308e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
17318e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_SUSPENDED: {
17328e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                long contactId = mOpenHelper.getContactId(rawContactId);
1733f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
17348e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                if (contactId != 0) {
17358e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                    mContactAggregator.updateAggregateData(contactId);
17368e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                }
1737f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
17388e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
1739f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
17408e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_IMMEDITATE: {
17418e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                long contactId = mOpenHelper.getContactId(rawContactId);
1742421782cb554e5050cf62a86b98df6520038dcd15Dmitri Plotnikov                mContactAggregator.markForAggregation(rawContactId);
17438e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                mContactAggregator.aggregateContact(mDb, rawContactId, contactId);
1744f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
17458e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
1746f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        }
1747f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
1748f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
1749a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
17505ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * Returns the group id of the group with sourceId and the same account as rawContactId.
17519261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * If the group doesn't already exist then it is first created,
17529261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param db SQLiteDatabase to use for this operation
17535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * @param rawContactId the contact this group is associated with
17549261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param sourceId the sourceIf of the group to query or create
17559261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @return the group id of the existing or created group
17569261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalArgumentException if the contact is not associated with an account
17579261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalStateException if a group needs to be created but the creation failed
17589261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     */
17595ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private long getOrMakeGroup(SQLiteDatabase db, long rawContactId, String sourceId) {
17609261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        Account account = null;
17616cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Cursor c = db.query(ContactsQuery.TABLE, ContactsQuery.PROJECTION, RawContacts._ID + "="
17625ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                + rawContactId, null, null, null, null);
17639261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
17649261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            if (c.moveToNext()) {
176567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                final String accountName = c.getString(ContactsQuery.ACCOUNT_NAME);
176667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                final String accountType = c.getString(ContactsQuery.ACCOUNT_TYPE);
17679261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
17689261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    account = new Account(accountName, accountType);
17699261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
17709261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
17719261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
17729261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
17739261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
17749261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        if (account == null) {
17759261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            throw new IllegalArgumentException("if the groupmembership only "
17769261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "has a sourceid the the contact must be associate with "
17779261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "an account");
17789261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
17799261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
17809261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // look up the group that contains this sourceId and has the same account name and type
17815ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        // as the contact refered to by rawContactId
17826cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        c = db.query(Tables.GROUPS, new String[]{RawContacts._ID},
17839261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Clauses.GROUP_HAS_ACCOUNT_AND_SOURCE_ID,
1784df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                new String[]{sourceId, account.name, account.type}, null, null, null);
17859261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
17869261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            if (c.moveToNext()) {
17879261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                return c.getLong(0);
17889261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            } else {
17899261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                ContentValues groupValues = new ContentValues();
1790df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                groupValues.put(Groups.ACCOUNT_NAME, account.name);
1791df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                groupValues.put(Groups.ACCOUNT_TYPE, account.type);
17929261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                groupValues.put(Groups.SOURCE_ID, sourceId);
17939261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                long groupId = db.insert(Tables.GROUPS, Groups.ACCOUNT_NAME, groupValues);
17949261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (groupId < 0) {
17959261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    throw new IllegalStateException("unable to create a new group with "
17969261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            + "this sourceid: " + groupValues);
17979261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
17989261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                return groupId;
17999261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
18009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
18019261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
18029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
18039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    }
18049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
18059261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /**
180620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     * Delete data row by row so that fixing of primaries etc work correctly.
180720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     */
180873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private int deleteData(String selection, String[] selectionArgs,
180973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            boolean markRawContactAsDirty) {
181020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int count = 0;
181120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1812de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
1813de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
181414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, selection, selectionArgs, null);
1815de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        try {
1816de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            while(c.moveToNext()) {
181714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
181814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
1819a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                DataRowHandler rowHandler = getDataRowHandler(mimeType);
1820a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                count += rowHandler.delete(mDb, c);
182188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                if (markRawContactAsDirty) {
182288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                    setRawContactDirty(rawContactId);
1823a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                    if (rowHandler.isAggregationRequired()) {
1824a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                        triggerAggregation(rawContactId);
1825a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                    }
182688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                }
182720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
182820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
1829de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            c.close();
183020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
183120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
183220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        return count;
183320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
183420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
183588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov    /**
183688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     * Delete a data row provided that it is one of the allowed mime types.
183788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     */
183820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    public int deleteData(long dataId, String[] allowedMimeTypes) {
1839f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
184088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
184188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
184214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, Data._ID + "=" + dataId, null,
184314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                null);
1844f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
184520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        try {
184620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!c.moveToFirst()) {
184720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                return 0;
184820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
184920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
185014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
185120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            boolean valid = false;
185220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            for (int i = 0; i < allowedMimeTypes.length; i++) {
185320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                if (TextUtils.equals(mimeType, allowedMimeTypes[i])) {
185420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    valid = true;
185520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    break;
185620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                }
185720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
185820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
185920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!valid) {
18607a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException("Data type mismatch: expected "
186120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                        + Lists.newArrayList(allowedMimeTypes));
186220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
186320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1864a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            DataRowHandler rowHandler = getDataRowHandler(mimeType);
1865a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            int count = rowHandler.delete(mDb, c);
18668e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
1867a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            if (rowHandler.isAggregationRequired()) {
1868a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                triggerAggregation(rawContactId);
1869a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            }
18708e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            return count;
187120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
187220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            c.close();
187320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
187420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
187520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
187620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    /**
1877ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Inserts an item in the groups table
1878ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
187973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private long insertGroup(ContentValues values, Account account, boolean markAsDirty) {
1880ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        ContentValues overriddenValues = new ContentValues(values);
1881ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        if (!resolveAccount(overriddenValues, account)) {
1882ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            return -1;
1883ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        }
1884ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1885ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Replace package with internal mapping
188667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        final String packageName = overriddenValues.getAsString(Groups.RES_PACKAGE);
188767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        if (packageName != null) {
188867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            overriddenValues.put(GroupsColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
188967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        }
189067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        overriddenValues.remove(Groups.RES_PACKAGE);
1891ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
189273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (markAsDirty) {
189373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            overriddenValues.put(Groups.DIRTY, 1);
189473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
189573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1896ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        long result = mDb.insert(Tables.GROUPS, Groups.TITLE, overriddenValues);
1897ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey
1898ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        if (overriddenValues.containsKey(Groups.GROUP_VISIBLE)) {
1899ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey            mOpenHelper.updateAllVisible();
1900ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        }
1901ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey
1902ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        return result;
1903ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
1904ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1905e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    private long insertSettings(ContentValues values) {
1906e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final long id = mDb.insert(Tables.SETTINGS, null, values);
1907e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        if (values.containsKey(Settings.UNGROUPED_VISIBLE)) {
1908e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey            mOpenHelper.updateAllVisible();
1909e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
1910e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return id;
1911e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
1912e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
1913ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
19141f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     * Inserts a presence update.
19151f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     */
191670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    public long insertPresence(ContentValues values) {
19171f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        final String handle = values.getAsString(Presence.IM_HANDLE);
19184dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        if (TextUtils.isEmpty(handle) || !values.containsKey(Presence.PROTOCOL)) {
19194dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required");
19204dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        }
19214dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov
19224dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        final long protocol = values.getAsLong(Presence.PROTOCOL);
19234dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        String customProtocol = null;
19244dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov
19254dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        if (protocol == Im.PROTOCOL_CUSTOM) {
19264dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            customProtocol = values.getAsString(Presence.CUSTOM_PROTOCOL);
19274dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            if (TextUtils.isEmpty(customProtocol)) {
19284dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                throw new IllegalArgumentException(
19294dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                        "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM");
19304dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            }
19311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
19321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
19331f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        // TODO: generalize to allow other providers to match against email
19344dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol;
19351f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
193670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        StringBuilder selection = new StringBuilder();
19371f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String[] selectionArgs;
19381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        if (matchEmail) {
19394dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            selection.append(
19404dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    "((" + MimetypesColumns.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'"
19414dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + " AND " + Im.PROTOCOL + "=?"
19424dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + " AND " + Im.DATA + "=?");
19434dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            if (customProtocol != null) {
19444dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                selection.append(" AND " + Im.CUSTOM_PROTOCOL + "=");
19454dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(selection, customProtocol);
19464dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            }
19474dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            selection.append(") OR ("
19484dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + MimetypesColumns.MIMETYPE + "='" + Email.CONTENT_ITEM_TYPE + "'"
19494dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + " AND " + Email.DATA + "=?"
19504dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + "))");
19514dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            selectionArgs = new String[] { String.valueOf(protocol), handle, handle };
19521f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } else {
19534dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            selection.append(
19544dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    MimetypesColumns.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'"
19554dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + " AND " + Im.PROTOCOL + "=?"
19564dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + " AND " + Im.DATA + "=?");
19574dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            if (customProtocol != null) {
19584dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                selection.append(" AND " + Im.CUSTOM_PROTOCOL + "=");
19594dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(selection, customProtocol);
19604dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            }
19614dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov
19624dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            selectionArgs = new String[] { String.valueOf(protocol), handle };
19631f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
19641f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
196570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (values.containsKey(Presence.DATA_ID)) {
196670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            selection.append(" AND " + DataColumns.CONCRETE_ID + "=")
196770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                    .append(values.getAsLong(Presence.DATA_ID));
196870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
196970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
197000ec508630251d6c6e3746469c9428f5a8cd5996Jeff Sharkey        selection.append(" AND ").append(getContactsRestrictions());
197170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
19721f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        long dataId = -1;
19735ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        long rawContactId = -1;
1974e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        long contactId = -1;
197570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
19761f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        Cursor cursor = null;
19771f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        try {
1978de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION,
197970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                    selection.toString(), selectionArgs, null, null, null);
19801f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            if (cursor.moveToFirst()) {
198167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                dataId = cursor.getLong(DataContactsQuery.DATA_ID);
19825ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID);
1983e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                contactId = cursor.getLong(DataContactsQuery.CONTACT_ID);
19841f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            } else {
19851f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                // No contact found, return a null URI
19861f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                return -1;
19871f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
19881f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } finally {
198931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            if (cursor != null) {
199031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                cursor.close();
199131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
19921f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
19931f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
19941f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        values.put(Presence.DATA_ID, dataId);
19954dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        values.put(PresenceColumns.RAW_CONTACT_ID, rawContactId);
19961f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
19971f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        // Insert the presence update
1998de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        long presenceId = mDb.replace(Tables.PRESENCE, null, values);
1999e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
2000e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        if (contactId != -1) {
2001e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            if (values.containsKey(Presence.PRESENCE_STATUS)) {
2002e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceReplace.bindLong(1, contactId);
2003e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceReplace.bindLong(2, contactId);
2004e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceReplace.execute();
2005e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            }
2006e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            String status = values.getAsString(Presence.PRESENCE_CUSTOM_STATUS);
2007e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            if (status != null) {
2008e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceStatusUpdate.bindString(1, status);
2009e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceStatusUpdate.bindLong(2, contactId);
2010e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceStatusUpdate.execute();
2011e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            }
2012e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        }
20131f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        return presenceId;
20141f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    }
20151f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
20164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
2017de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
2018508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        final int match = sUriMatcher.match(uri);
2019508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        switch (match) {
202035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
2021de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mOpenHelper.getSyncState().delete(mDb, selection, selectionArgs);
202235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2023d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
2024d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
20256bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
2026d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                // Remove references to the contact first
20276bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                ContentValues values = new ContentValues();
2028d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values.putNull(RawContacts.CONTACT_ID);
2029de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                mDb.update(Tables.RAW_CONTACTS, values,
2030d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        RawContacts.CONTACT_ID + "=" + contactId, null);
20316bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
2032de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.delete(Tables.CONTACTS, BaseColumns._ID + "=" + contactId, null);
20336bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
20346bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
20352971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            case RAW_CONTACTS: {
20362971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                final boolean permanently =
20372971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        readBooleanQueryParameter(uri, RawContacts.DELETE_PERMANENTLY, false);
20382971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                int numDeletes = 0;
20392971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                Cursor c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID},
2040e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs, null, null, null);
20412971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                try {
20422971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    while (c.moveToNext()) {
20432971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        final long rawContactId = c.getLong(0);
20442971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        numDeletes += deleteRawContact(rawContactId, permanently);
20452971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    }
20462971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                } finally {
20472971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    c.close();
20482971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                }
20492971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return numDeletes;
20502971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            }
20512971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana
20525ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
20532971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                final boolean permanently =
20542971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        readBooleanQueryParameter(uri, RawContacts.DELETE_PERMANENTLY, false);
20552971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                final long rawContactId = ContentUris.parseId(uri);
20562971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return deleteRawContact(rawContactId, permanently);
2057508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
2058508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
205920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
2060944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                return deleteData(appendAccountToSelection(uri, selection), selectionArgs,
2061944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                        shouldMarkRawContactAsDirty(uri));
206220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
206320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2064508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            case DATA_ID: {
2065508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey                long dataId = ContentUris.parseId(uri);
2066f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov                return deleteData(Data._ID + "=" + dataId, null, shouldMarkRawContactAsDirty(uri));
2067ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2068ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2069ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
20702971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                boolean markAsDirty = shouldMarkGroupAsDirty(uri);
20712971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                final boolean deletePermanently =
20722971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        readBooleanQueryParameter(uri, Groups.DELETE_PERMANENTLY, false);
20732971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return deleteGroup(ContentUris.parseId(uri), markAsDirty, deletePermanently);
20742971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            }
20752971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana
20762971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            case GROUPS: {
20772971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                boolean markAsDirty = shouldMarkGroupAsDirty(uri);
20786f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov                final boolean permanently =
20792971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        readBooleanQueryParameter(uri, RawContacts.DELETE_PERMANENTLY, false);
20802971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                int numDeletes = 0;
20812971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups._ID},
2082e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs, null, null, null);
20832971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                try {
20842971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    while (c.moveToNext()) {
20852971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        numDeletes += deleteGroup(c.getLong(0), markAsDirty, permanently);
20862971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    }
20872971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                } finally {
20882971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    c.close();
20892971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                }
20902971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return numDeletes;
2091508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
2092508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
2093eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
2094e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                return deleteSettings(selection, selectionArgs);
2095eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
2096eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
20971f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            case PRESENCE: {
2098eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                return mDb.delete(Tables.PRESENCE, selection, selectionArgs);
20991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
21001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2101508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            default:
21023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                return mLegacyApiSupport.delete(uri, selection, selectionArgs);
2103508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        }
21044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
21054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
21062971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana    private boolean readBooleanQueryParameter(Uri uri, String name, boolean defaultValue) {
21072971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana        final String flag = uri.getQueryParameter(name);
21082971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana        return flag == null
21092971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                ? defaultValue
21102971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                : (!"false".equals(flag.toLowerCase()) && !"0".equals(flag.toLowerCase()));
211194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
211294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
211373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private int deleteGroup(long groupId, boolean markAsDirty, boolean permanently) {
211494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        final long groupMembershipMimetypeId = mOpenHelper
211594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
2116de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mDb.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "="
211794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "="
211894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupId, null);
211994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
212094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        try {
212194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            if (permanently) {
2122de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null);
212394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            } else {
212494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.clear();
212594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.put(Groups.DELETED, 1);
212673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                if (markAsDirty) {
212773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                    mValues.put(Groups.DIRTY, 1);
212873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                }
2129de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, null);
213094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            }
213194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        } finally {
213294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            mOpenHelper.updateAllVisible();
213394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
213494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
213594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
2136e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    private int deleteSettings(String selection, String[] selectionArgs) {
2137e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final int count = mDb.delete(Tables.SETTINGS, selection, selectionArgs);
2138e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        if (count > 0) {
2139e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey            mOpenHelper.updateAllVisible();
2140e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
2141e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return count;
2142e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
2143e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
21445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public int deleteRawContact(long rawContactId, boolean permanently) {
2145c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        // TODO delete aggregation exceptions
2146c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        mOpenHelper.removeContactIfSingleton(rawContactId);
214733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        if (permanently) {
214814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mDb.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null);
2149de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            return mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null);
215033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        } else {
215111944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov
215211944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov            // Clear out data used for aggregation - this deleted contact should not be aggregated
215311944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov            mDb.execSQL("DELETE FROM " + Tables.NAME_LOOKUP + " WHERE "
215411944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov                    + NameLookupColumns.RAW_CONTACT_ID + "=" + rawContactId);
215511944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov
215633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov            mValues.clear();
215794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            mValues.put(RawContacts.DELETED, 1);
2158c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
2159c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            mValues.putNull(RawContacts.CONTACT_ID);
216073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            mValues.put(RawContacts.DIRTY, 1);
21615ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return updateRawContact(rawContactId, mValues, null, null);
216233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        }
216333b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
216433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
2165f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana    private static Account readAccountFromQueryParams(Uri uri) {
21666cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String name = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
21676cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String type = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
2168f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(type)) {
2169f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana            return null;
2170f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        }
2171f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        return new Account(name, type);
2172f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana    }
2173f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana
21744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
2175de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int updateInTransaction(Uri uri, ContentValues values, String selection,
2176de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            String[] selectionArgs) {
217735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        int count = 0;
217800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
217900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        final int match = sUriMatcher.match(uri);
218000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        switch(match) {
218135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
2182de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mOpenHelper.getSyncState().update(mDb, values, selection, selectionArgs);
218335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2184d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            // TODO(emillar): We will want to disallow editing the contacts table at some point.
2185d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
2186944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                count = mDb.update(Tables.CONTACTS, values,
2187944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs);
218800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
218900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
219000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
2191d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
2192de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateContactData(ContentUris.parseId(uri), values);
2193c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                break;
2194c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar            }
2195c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
219620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
2197944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                count = updateData(uri, values, appendAccountToSelection(uri, selection),
2198944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                        selectionArgs, shouldMarkRawContactAsDirty(uri));
219920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                break;
220020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
2201c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
220220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA_ID: {
220373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                count = updateData(uri, values, selection, selectionArgs,
220473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        shouldMarkRawContactAsDirty(uri));
220500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
220600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
22077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
22085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
220973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                // TODO: security checks
2210e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                count = mDb.update(Tables.RAW_CONTACTS, values,
2211e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs);
22127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
22137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
22147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
22155ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
221633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
221733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                count = updateRawContact(rawContactId, values, selection, selectionArgs);
22187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
22197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
22207e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
2221ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
2222e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                count = updateGroups(values, appendAccountToSelection(uri, selection),
2223e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        selectionArgs, shouldMarkGroupAsDirty(uri));
2224ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2225ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2226ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2227ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
2228ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
222973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                String selectionWithId = (Groups._ID + "=" + groupId + " ")
223073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        + (selection == null ? "" : " AND " + selection);
2231de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateGroups(values, selectionWithId, selectionArgs,
223273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        shouldMarkGroupAsDirty(uri));
2233ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2234ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2235ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2236127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
2237de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateAggregationException(mDb, values);
2238b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
2239b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
2240b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
2241eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
2242e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                count = updateSettings(values, selection, selectionArgs);
2243eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
2244eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
2245eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
22467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            default:
2247f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.update(uri, values, selection, selectionArgs);
224800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        }
224900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
225000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        return count;
22514f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
22524f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
2253de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    private int updateGroups(ContentValues values, String selectionWithId,
225473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            String[] selectionArgs, boolean markAsDirty) {
225573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
225673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        ContentValues updatedValues;
225773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (markAsDirty) {
225873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = mValues;
225973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.clear();
226073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.putAll(values);
226173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.put(Groups.DIRTY, 1);
226273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        } else {
226373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = values;
226473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
226573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
2266ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        int count = mDb.update(Tables.GROUPS, updatedValues, selectionWithId, selectionArgs);
226794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
226894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        // If changing visibility, then update contacts
2269ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) {
227094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            mOpenHelper.updateAllVisible();
227194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
227294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        return count;
227394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
227494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
2275e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    private int updateSettings(ContentValues values, String selection, String[] selectionArgs) {
2276e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final int count = mDb.update(Tables.SETTINGS, values, selection, selectionArgs);
2277e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        if (values.containsKey(Settings.UNGROUPED_VISIBLE)) {
2278e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey            mOpenHelper.updateAllVisible();
2279e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
2280e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return count;
2281e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
2282e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
22835ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private int updateRawContact(long rawContactId, ContentValues values, String selection,
228433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov            String[] selectionArgs) {
228573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
228673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        // TODO: security checks
22875ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        String selectionWithId = (RawContacts._ID + " = " + rawContactId + " ")
228833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                + (selection == null ? "" : " AND " + selection);
22895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int count = mDb.update(Tables.RAW_CONTACTS, values, selectionWithId, selectionArgs);
22905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (count != 0) {
22915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (values.containsKey(RawContacts.ACCOUNT_TYPE)
22925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    || values.containsKey(RawContacts.ACCOUNT_NAME)
22935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    || values.containsKey(RawContacts.SOURCE_ID)) {
22945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                triggerAggregation(rawContactId);
22955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
22965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
22975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return count;
229833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
229933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
2300321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    private int updateData(Uri uri, ContentValues values, String selection,
230173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            String[] selectionArgs, boolean markRawContactAsDirty) {
230220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.clear();
230320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.putAll(values);
230420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data._ID);
23055ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mValues.remove(Data.RAW_CONTACT_ID);
230620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
230720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
230820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        String packageName = values.getAsString(Data.RES_PACKAGE);
230920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        if (packageName != null) {
231020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.remove(Data.RES_PACKAGE);
231120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
231220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
231320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
231470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsSuperPrimary = mValues.containsKey(Data.IS_SUPER_PRIMARY);
231570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsPrimary = mValues.containsKey(Data.IS_PRIMARY);
231620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
231720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // Remove primary or super primary values being set to 0. This is disallowed by the
231820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // content provider.
231970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsSuperPrimary && mValues.getAsInteger(Data.IS_SUPER_PRIMARY) == 0) {
232020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsSuperPrimary = false;
232170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_SUPER_PRIMARY);
232220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
232370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsPrimary && mValues.getAsInteger(Data.IS_PRIMARY) == 0) {
232420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsPrimary = false;
232570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_PRIMARY);
232620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
232720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2328653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        int count = 0;
232920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2330653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
2331653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        // so we don't need to worry about updating data we don't have permission to read.
233214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(uri, DataUpdateQuery.COLUMNS, selection, selectionArgs, null);
2333653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        try {
2334653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            while(c.moveToNext()) {
2335653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                count += updateData(mValues, c, markRawContactAsDirty);
233620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
2337653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        } finally {
2338653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            c.close();
233920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
234020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2341653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        return count;
234220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
234320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2344653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    private int updateData(ContentValues values, Cursor c, boolean markRawContactAsDirty) {
2345653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        if (values.size() == 0) {
2346653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return 0;
2347321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        }
2348653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
234914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        final String mimeType = c.getString(DataUpdateQuery.MIMETYPE);
2350a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        DataRowHandler rowHandler = getDataRowHandler(mimeType);
2351a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        rowHandler.update(mDb, values, c, markRawContactAsDirty);
23528e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
2353a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        if (rowHandler.isAggregationRequired()) {
2354a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            triggerAggregation(rawContactId);
2355a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
23568e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
2357653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        return 1;
2358321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    }
2359321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana
2360de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    private int updateContactData(long contactId, ContentValues values) {
2361d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
2362d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // First update all constituent contacts
2363f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        ContentValues optionValues = new ContentValues(5);
23646cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyStringValue(optionValues, RawContacts.CUSTOM_RINGTONE,
2365d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.CUSTOM_RINGTONE);
23666cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.SEND_TO_VOICEMAIL,
2367d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.SEND_TO_VOICEMAIL);
23686cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.LAST_TIME_CONTACTED,
2369d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.LAST_TIME_CONTACTED);
23706cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.TIMES_CONTACTED,
2371d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.TIMES_CONTACTED);
23726cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.STARRED,
2373d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.STARRED);
2374d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
2375d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // Nothing to update - just return
2376d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        if (optionValues.size() == 0) {
2377d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov            return 0;
2378d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        }
2379d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
2380c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey        if (optionValues.containsKey(RawContacts.STARRED)) {
2381c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey            // Mark dirty when changing starred to trigger sync
2382c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey            optionValues.put(RawContacts.DIRTY, 1);
2383c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey        }
2384c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey
2385de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mDb.update(Tables.RAW_CONTACTS, optionValues,
2386d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                RawContacts.CONTACT_ID + "=" + contactId, null);
2387de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return mDb.update(Tables.CONTACTS, values, Contacts._ID + "=" + contactId, null);
2388f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
2389d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
2390d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    public void updateContactTime(long contactId, long lastTimeContacted) {
2391f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        mLastTimeContactedUpdate.bindLong(1, lastTimeContacted);
2392d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        mLastTimeContactedUpdate.bindLong(2, contactId);
2393f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        mLastTimeContactedUpdate.execute();
2394d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov    }
2395d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
23965ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static class RawContactPair {
23975ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        final long rawContactId1;
23985ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        final long rawContactId2;
2399127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
2400127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        /**
24015ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov         * Constructor that ensures that this.rawContactId1 &lt; this.rawContactId2
2402127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov         */
24035ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public RawContactPair(long rawContactId1, long rawContactId2) {
24045ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            if (rawContactId1 < rawContactId2) {
24055ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId1 = rawContactId1;
24065ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId2 = rawContactId2;
2407127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            } else {
24085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId2 = rawContactId1;
24095ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId1 = rawContactId2;
2410127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            }
2411127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        }
2412127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov    }
241380c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
2414127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov    private int updateAggregationException(SQLiteDatabase db, ContentValues values) {
2415127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        int exceptionType = values.getAsInteger(AggregationExceptions.TYPE);
2416d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        long contactId = values.getAsInteger(AggregationExceptions.CONTACT_ID);
24175ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        long rawContactId = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID);
241880c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
24193cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        // First, we build a list of rawContactID-rawContactID pairs for the given contact.
24205ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        ArrayList<RawContactPair> pairs = new ArrayList<RawContactPair>();
2421d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        Cursor c = db.query(ContactsQuery.TABLE, ContactsQuery.PROJECTION, RawContacts.CONTACT_ID
2422d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + "=" + contactId, null, null, null, null);
2423127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        try {
2424127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            while (c.moveToNext()) {
24255ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long aggregatedContactId = c.getLong(ContactsQuery.RAW_CONTACT_ID);
24265ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                if (aggregatedContactId != rawContactId) {
24275ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    pairs.add(new RawContactPair(aggregatedContactId, rawContactId));
2428e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov                }
2429b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
2430b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        } finally {
2431b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            c.close();
2432b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        }
2433127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
2434127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // Now we iterate through all contact pairs to see if we need to insert/delete/update
2435127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // the corresponding exception
2436127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        ContentValues exceptionValues = new ContentValues(3);
2437127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        exceptionValues.put(AggregationExceptions.TYPE, exceptionType);
24385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        for (RawContactPair pair : pairs) {
2439127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            final String whereClause =
24405ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    AggregationExceptionColumns.RAW_CONTACT_ID1 + "=" + pair.rawContactId1 + " AND "
24415ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + AggregationExceptionColumns.RAW_CONTACT_ID2 + "=" + pair.rawContactId2;
2442127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) {
2443127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                db.delete(Tables.AGGREGATION_EXCEPTIONS, whereClause, null);
2444127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            } else {
24455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                exceptionValues.put(AggregationExceptionColumns.RAW_CONTACT_ID1, pair.rawContactId1);
24465ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                exceptionValues.put(AggregationExceptionColumns.RAW_CONTACT_ID2, pair.rawContactId2);
2447127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID,
2448127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                        exceptionValues);
2449127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            }
2450127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        }
2451127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
2452421782cb554e5050cf62a86b98df6520038dcd15Dmitri Plotnikov        mContactAggregator.markForAggregation(rawContactId);
24538e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        mContactAggregator.aggregateContact(db, rawContactId,
24548e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                mOpenHelper.getContactId(rawContactId));
24558e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC
24568e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                || exceptionType == AggregationExceptions.TYPE_KEEP_OUT) {
24578e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            mContactAggregator.updateAggregateData(contactId);
24587a39bf269294a8130ddd463460b9b36cf4ff74a8Dmitri Plotnikov        }
2459127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
2460127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // The return value is fake - we just confirm that we made a change, not count actual
2461127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // rows changed.
2462127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        return 1;
2463b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    }
2464b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
2465619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2466619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
2467619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Test if a {@link String} value appears in the given list, and add to the
2468619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * array if the value doesn't already appear.
2469619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
2470619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private String[] assertContained(String[] array, String value) {
2471ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        if (array != null && !mOpenHelper.isInProjection(array, value)) {
2472619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            String[] newArray = new String[array.length + 1];
2473619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            System.arraycopy(array, 0, newArray, 0, array.length);
2474619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            newArray[array.length] = value;
2475619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            array = newArray;
2476619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
2477619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        return array;
2478619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
2479619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
24804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
24814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
24824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            String sortOrder) {
24830b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov
24844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
248535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2486d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
24871f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String groupBy = null;
2488c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limit = getLimit(uri);
2489c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2490619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // TODO: Consider writing a test case for RestrictionExceptions when you
2491619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // write a new query() block to make sure it protects restricted data.
2492a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
24934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
249435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
249535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                return mOpenHelper.getSyncState().query(db, projection, selection,  selectionArgs,
249635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                        sortOrder);
249735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2498d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
2499ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
2500619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                break;
2501619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            }
2502619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2503d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
25044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
2505ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
25064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Contacts._ID + "=" + contactId);
25076bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
25086bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
25096bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
25105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            case CONTACTS_LOOKUP:
25115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            case CONTACTS_LOOKUP_ID: {
25125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                List<String> pathSegments = uri.getPathSegments();
25135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int segmentCount = pathSegments.size();
25145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segmentCount < 3) {
25155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    throw new IllegalArgumentException("URI " + uri + " is missing a lookup key");
25165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
25175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String lookupKey = pathSegments.get(2);
25185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segmentCount == 4) {
25195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    long contactId = Long.parseLong(pathSegments.get(3));
25205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder();
25215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    setTablesAndProjectionMapForContacts(lookupQb, projection);
25225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    lookupQb.appendWhere(Contacts._ID + "=" + contactId + " AND " +
25235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            Contacts.LOOKUP_KEY + "=");
25245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    lookupQb.appendWhereEscapeString(lookupKey);
25255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    Cursor c = query(db, lookupQb, projection, selection, selectionArgs, sortOrder,
25265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            groupBy, limit);
25275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (c.getCount() != 0) {
25285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        return c;
25295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
25305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
25315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    c.close();
25325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
25335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
25345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
25355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                qb.appendWhere(Contacts._ID + "=" + lookupContactIdByLookupKey(db, lookupKey));
25365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                break;
25375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
25385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
2539ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_FILTER: {
2540ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
2541ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
25424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
25434a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
2544e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    sb.append(Contacts._ID + " IN ");
2545e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    appendContactByFilterAsNestedQuery(sb, filterParam);
25464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(sb.toString());
2547ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
2548ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2549ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2550ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
2551ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_STREQUENT_FILTER:
2552ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_STREQUENT: {
25534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                String filterSql = null;
2554ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                if (match == CONTACTS_STREQUENT_FILTER
2555d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        && uri.getPathSegments().size() > 3) {
25564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
25574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
2558e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    sb.append(Contacts._ID + " IN ");
2559e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    appendContactByFilterAsNestedQuery(sb, filterParam);
25604a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    filterSql = sb.toString();
25614a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
25624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
2563ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
2564ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
25654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                // Build the first query for starred
25664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
25674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
2568d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2569d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                final String starredQuery = qb.buildQuery(projection, Contacts.STARRED + "=1",
25704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
2571d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2572d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Build the second query for frequent
2573d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                qb = new SQLiteQueryBuilder();
2574ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
25754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
25764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
2577d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2578d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String frequentQuery = qb.buildQuery(projection,
2579d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        Contacts.TIMES_CONTACTED + " > 0 AND (" + Contacts.STARRED
2580d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        + " = 0 OR " + Contacts.STARRED + " IS NULL)",
25814a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
2582d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2583d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Put them together
2584d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery},
2585d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        STREQUENT_ORDER_BY, STREQUENT_LIMIT);
25864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                Cursor c = db.rawQuery(query, null);
25874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (c != null) {
2588d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                    c.setNotificationUri(getContext().getContentResolver(),
2589d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                            ContactsContract.AUTHORITY_URI);
2590d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2591d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                return c;
2592d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar            }
2593d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2594ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_GROUP: {
2595ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
2596b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                if (uri.getPathSegments().size() > 2) {
25974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(sContactsInGroupSelect);
25984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
2599b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                }
2600b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                break;
2601b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            }
2602b67163a1088f09c59f324350662eb18772fac6b6Evan Millar
2603d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_DATA: {
26044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
26054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
26064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
26094a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=" + contactId);
26106bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
26116bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
261200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
2613ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_PHOTO: {
26143653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
26153653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
26163653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26173653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26183653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
26193653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=" + contactId);
26203653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID);
26213653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                break;
26223653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov            }
26233653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
26244a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case PHONES: {
26254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26264a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26274a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
26282815f58f72f109790585931f601a63ddc02536a5Evan Millar                break;
26292815f58f72f109790585931f601a63ddc02536a5Evan Millar            }
26302815f58f72f109790585931f601a63ddc02536a5Evan Millar
2631ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case PHONES_FILTER: {
26324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26334a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
2634ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                qb.appendWhere(Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
2635ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
26364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
26374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
26384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    sb.append(Data.RAW_CONTACT_ID + " IN ");
26394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    appendRawContactsByFilterAsNestedQuery(sb, filterParam, null);
26404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(" AND " + sb);
2641ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
2642ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2643ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2644ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
26454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case EMAILS: {
26464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
26494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                break;
26504a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            }
26514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
26524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case EMAILS_FILTER: {
26534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26554a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
26564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (uri.getPathSegments().size() > 2) {
26574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(" AND " + CommonDataKinds.Email.DATA + "=");
26584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhereEscapeString(uri.getLastPathSegment());
26594a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
2660ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2661ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2662ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
2663ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case POSTALS: {
26644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + StructuredPostal.CONTENT_ITEM_TYPE + "'");
2667ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2668ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2669ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
26705ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
26714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getRawContactView());
2672d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sRawContactsProjectionMap);
26734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
26744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
26754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
26765ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
26775ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
26784a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getRawContactView());
2679d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sRawContactsProjectionMap);
26804a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(RawContacts._ID + "=" + rawContactId);
26814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
26824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
26834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
26845ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
26855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = Long.parseLong(uri.getPathSegments().get(1));
26864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.RAW_CONTACT_ID + "=" + rawContactId);
2689e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
2690e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
2691e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
2692e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            case DATA: {
26934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26954a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
2696e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
2697e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
2698e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
26994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            case DATA_ID: {
27004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
27014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
27024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data._ID + "=" + ContentUris.parseId(uri));
27034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
27044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
27054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
2706a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov            case DATA_WITH_PRESENCE: {
2707a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov                qb.setTables(mOpenHelper.getDataView() + " data"
2708e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + " LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE
2709e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + " ON (" + AggregatedPresenceColumns.CONTACT_ID + "="
2710e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                                + RawContacts.CONTACT_ID + ")");
2711a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov                qb.setProjectionMap(sDataWithPresenceProjectionMap);
2712a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov                break;
2713a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov            }
2714a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov
2715a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case PHONE_LOOKUP: {
27164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
2717a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                if (TextUtils.isEmpty(sortOrder)) {
2718a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // Default the sort order to something reasonable so we get consistent
2719a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // results when callers don't request an ordering
2720e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                    sortOrder = RawContactsColumns.CONCRETE_ID;
2721a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                }
2722a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2723e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : "";
2724e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                mOpenHelper.buildPhoneLookupAndContactQuery(qb, number);
2725e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                qb.setProjectionMap(sPhoneLookupProjectionMap);
2726e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov
2727e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                // Phone lookup cannot be combined with a selection
2728e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                selection = null;
2729e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                selectionArgs = null;
2730a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
2731a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
2732a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2733ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
2734ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2735ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
2736ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2737ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2738ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2739ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
2740ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
2741ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2742ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
2743ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.appendWhere(GroupsColumns.CONCRETE_ID + "=" + groupId);
2744ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2745ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2746ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2747ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_SUMMARY: {
274899a9b5ec879f6cd6876f7f6b680b82d8304e6b92Dmitri Plotnikov                qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2749ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsSummaryProjectionMap);
2750ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                groupBy = GroupsColumns.CONCRETE_ID;
2751ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2752ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2753ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2754b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
27555ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.setTables(Tables.AGGREGATION_EXCEPTIONS_JOIN_RAW_CONTACTS);
2756b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                qb.setProjectionMap(sAggregationExceptionsProjectionMap);
2757b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
2758b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
2759b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
276031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_SUGGESTIONS: {
2761d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
276231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                final int maxSuggestions;
2763d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                if (limit != null) {
2764d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                    maxSuggestions = Integer.parseInt(limit);
276531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                } else {
276631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                    maxSuggestions = DEFAULT_MAX_SUGGESTIONS;
276731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                }
276831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
2769d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                return mContactAggregator.queryAggregationSuggestions(contactId, projection,
2770d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        sContactsProjectionMap, maxSuggestions);
277131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
277231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
2773eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
2774eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                qb.setTables(Tables.SETTINGS);
2775eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                qb.setProjectionMap(sSettingsProjectionMap);
2776e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
2777e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                // When requesting specific columns, this query requires
2778e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                // late-binding of the GroupMembership MIME-type.
2779e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                final String groupMembershipMimetypeId = Long.toString(mOpenHelper
2780e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                        .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE));
2781ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                if (mOpenHelper.isInProjection(projection, Settings.UNGROUPED_COUNT)) {
2782e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                    selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId);
2783e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                }
2784ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                if (mOpenHelper.isInProjection(projection, Settings.UNGROUPED_WITH_PHONES)) {
2785e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                    selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId);
2786e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                }
2787e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
2788eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
2789eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
2790eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
27915ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case PRESENCE: {
2792373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setTables(Tables.PRESENCE);
2793373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setProjectionMap(sPresenceProjectionMap);
27945ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
27955ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
27965ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
27975ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case PRESENCE_ID: {
2798373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setTables(Tables.PRESENCE);
2799373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setProjectionMap(sPresenceProjectionMap);
2800373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.appendWhere(Presence._ID + "=" + ContentUris.parseId(uri));
28015ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
28025ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
28035ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
2804c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS: {
2805a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov                return mGlobalSearchSupport.handleSearchSuggestionsQuery(db, uri, limit);
2806c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
2807c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2808c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT: {
2809b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
2810b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                return mGlobalSearchSupport.handleSearchShortcutRefresh(db, contactId, projection);
2811c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
2812c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
28131b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS:
28141b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
28151b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
28161b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
28171b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
28181b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_WITH_PHONES:
28191b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
28201b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
28211b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1");
28221b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
28231b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
28241b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_FAVORITES:
28251b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
28261b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
28271b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(Contacts.STARRED + "=1");
28281b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
28291b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
28301b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_GROUP_NAME:
28311b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
28321b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
28331b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(sContactsInGroupSelect);
28341b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
28351b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
28361b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
28374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            default:
2838f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.query(uri, projection, selection, selectionArgs,
2839c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                        sortOrder, limit);
28404f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
28414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
28425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit);
28435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
28445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
28455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection,
28465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            String selection, String[] selectionArgs, String sortOrder, String groupBy,
28475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            String limit) {
2848038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        if (projection != null && projection.length == 1
2849038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana                && BaseColumns._COUNT.equals(projection[0])) {
2850038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            qb.setProjectionMap(sCountProjectionMap);
2851038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        }
28525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null,
28535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sortOrder, limit);
28544f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        if (c != null) {
28554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI);
28564f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
28574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        return c;
28584f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
28594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
28605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) {
28615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        ContactLookupKey key = new ContactLookupKey();
28625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        ArrayList<LookupKeySegment> segments = key.parse(lookupKey);
28635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
28645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long contactId = lookupContactIdBySourceIds(db, segments);
28655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (contactId == -1) {
28665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            contactId = lookupContactIdByDisplayNames(db, segments);
28675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
28685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
28695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return contactId;
28705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
28715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
28725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private interface LookupBySourceIdQuery {
28735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String TABLE = Tables.RAW_CONTACTS;
28745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
28755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String COLUMNS[] = {
28765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.CONTACT_ID,
28775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
28785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
28795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.SOURCE_ID
28805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        };
28815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
28825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int CONTACT_ID = 0;
28835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_TYPE = 1;
28845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_NAME = 2;
28855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int SOURCE_ID = 3;
28865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
28875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
28885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdBySourceIds(SQLiteDatabase db,
28895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                ArrayList<LookupKeySegment> segments) {
28905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int sourceIdCount = 0;
28915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
28925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
28935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.sourceIdLookup) {
28945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sourceIdCount++;
28955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
28965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
28975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
28985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (sourceIdCount == 0) {
28995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return -1;
29005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
29015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        // First try sync ids
29035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
29045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(RawContacts.SOURCE_ID + " IN (");
29055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
29065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
29075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.sourceIdLookup) {
29085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(sb, segment.key);
29095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sb.append(",");
29105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
29115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
29125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.setLength(sb.length() - 1);      // Last comma
29135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL");
29145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS,
29165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                 sb.toString(), null, null, null, null);
29175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        try {
29185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            while (c.moveToNext()) {
29195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountType = c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE);
29205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME);
29215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int accountHashCode =
29225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        ContactLookupKey.getAccountHashCode(accountType, accountName);
29235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID);
29245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                for (int i = 0; i < segments.size(); i++) {
29255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    LookupKeySegment segment = segments.get(i);
29265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (segment.sourceIdLookup && accountHashCode == segment.accountHashCode
29275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            && segment.key.equals(sourceId)) {
29285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID);
29295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        break;
29305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
29315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
29325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
29335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } finally {
29345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            c.close();
29355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
29365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return getMostReferencedContactId(segments);
29385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
29395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private interface LookupByDisplayNameQuery {
29415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS;
29425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String COLUMNS[] = {
29445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.CONTACT_ID,
29455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
29465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
29475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                NameLookupColumns.NORMALIZED_NAME
29485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        };
29495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int CONTACT_ID = 0;
29515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_TYPE = 1;
29525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_NAME = 2;
29535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int NORMALIZED_NAME = 3;
29545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
29555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdByDisplayNames(SQLiteDatabase db,
29575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                ArrayList<LookupKeySegment> segments) {
29585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int displayNameCount = 0;
29595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
29605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
29615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (!segment.sourceIdLookup) {
29625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                displayNameCount++;
29635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
29645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
29655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (displayNameCount == 0) {
29675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return -1;
29685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
29695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        // First try sync ids
29715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
29725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(NameLookupColumns.NORMALIZED_NAME + " IN (");
29735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
29745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
29755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (!segment.sourceIdLookup) {
29765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(sb, segment.key);
29775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sb.append(",");
29785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
29795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
29805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.setLength(sb.length() - 1);      // Last comma
29815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY
29825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                + " AND " + RawContacts.CONTACT_ID + " NOT NULL");
29835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS,
29855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                 sb.toString(), null, null, null, null);
29865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        try {
29875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            while (c.moveToNext()) {
29885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountType = c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE);
29895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME);
29905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int accountHashCode =
29915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        ContactLookupKey.getAccountHashCode(accountType, accountName);
29925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME);
29935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                for (int i = 0; i < segments.size(); i++) {
29945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    LookupKeySegment segment = segments.get(i);
29955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (!segment.sourceIdLookup && accountHashCode == segment.accountHashCode
29965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            && segment.key.equals(name)) {
29975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID);
29985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        break;
29995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
30005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
30015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
30025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } finally {
30035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            c.close();
30045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
30055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return getMostReferencedContactId(segments);
30075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
30085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    /**
30105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov     * Returns the contact ID that is mentioned the highest number of times.
30115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov     */
30125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) {
30135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Collections.sort(segments);
30145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long bestContactId = -1;
30165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int bestRefCount = 0;
30175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long contactId = -1;
30195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int count = 0;
30205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int segmentCount = segments.size();
30225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segmentCount; i++) {
30235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
30245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.contactId != -1) {
30255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segment.contactId == contactId) {
30265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    count++;
30275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                } else {
30285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (count > bestRefCount) {
30295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        bestContactId = contactId;
30305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        bestRefCount = count;
30315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
30325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    contactId = segment.contactId;
30335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    count = 1;
30345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
30355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
30365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
30375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (count > bestRefCount) {
30385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return contactId;
30395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } else {
30405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return bestContactId;
30415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
30425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
30435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
3044ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, String[] projection) {
3045ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        String contactView = mOpenHelper.getContactView();
3046ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        boolean needsPresence = mOpenHelper.isInProjection(projection, Contacts.PRESENCE_STATUS,
3047ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                Contacts.PRESENCE_CUSTOM_STATUS);
3048ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        if (!needsPresence) {
3049ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            qb.setTables(contactView);
3050ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            qb.setProjectionMap(sContactsProjectionMap);
3051ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        } else {
3052ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            qb.setTables(contactView + " LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE + " ON ("
3053ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                    + Contacts._ID + " = " + AggregatedPresenceColumns.CONTACT_ID + ") ");
3054ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            qb.setProjectionMap(sContactsWithPresenceProjectionMap);
3055ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
3056ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        }
3057ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    }
3058ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
30594a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) {
30604a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
30614a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
30624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (!TextUtils.isEmpty(accountName)) {
30634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
30644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountName) + " AND "
30654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + RawContacts.ACCOUNT_TYPE + "="
30664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountType));
30674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        } else {
30684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere("1");
30694a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        }
30704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    }
30714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
3072e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong    private String appendAccountToSelection(Uri uri, String selection) {
3073e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
3074e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
3075e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        if (!TextUtils.isEmpty(accountName)) {
3076e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "="
3077e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + DatabaseUtils.sqlEscapeString(accountName) + " AND "
3078e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + RawContacts.ACCOUNT_TYPE + "="
3079e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + DatabaseUtils.sqlEscapeString(accountType));
3080e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            if (!TextUtils.isEmpty(selection)) {
3081e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(" AND (");
3082e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(selection);
3083e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(')');
3084e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            }
3085e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            return selectionSb.toString();
3086e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        } else {
3087e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            return selection;
3088e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        }
3089e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong    }
3090e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong
30917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
3092c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * Gets the value of the "limit" URI query parameter.
3093c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *
3094c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * @return A string containing a non-negative integer, or <code>null</code> if
3095c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *         the parameter is not set, or is set to an invalid value.
3096c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     */
3097c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private String getLimit(Uri url) {
3098c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limitParam = url.getQueryParameter("limit");
3099c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limitParam == null) {
3100c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
3101c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
3102c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        // make sure that the limit is a non-negative integer
3103c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        try {
3104c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            int l = Integer.parseInt(limitParam);
3105c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            if (l < 0) {
3106c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                Log.w(TAG, "Invalid limit parameter: " + limitParam);
3107c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return null;
3108c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
3109c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return String.valueOf(l);
3110c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        } catch (NumberFormatException ex) {
3111c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            Log.w(TAG, "Invalid limit parameter: " + limitParam);
3112c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
3113c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
3114c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
3115c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
311600ec508630251d6c6e3746469c9428f5a8cd5996Jeff Sharkey    String getContactsRestrictions() {
31174a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (mOpenHelper.hasRestrictedAccess()) {
311870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
311970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        } else {
31206cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            return RawContacts.IS_RESTRICTED + "=0";
312170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
312270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    }
312370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
312470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    public String getContactsRestrictionExceptionAsNestedQuery(String contactIdColumn) {
31254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (mOpenHelper.hasRestrictedAccess()) {
312670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
312767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        } else {
31285ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return "(SELECT " + RawContacts.IS_RESTRICTED + " FROM " + Tables.RAW_CONTACTS
31295ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + " WHERE " + RawContactsColumns.CONCRETE_ID + "=" + contactIdColumn + ")=0";
3130619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
3131619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
3132619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
3133b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    @Override
3134b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
3135b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        int match = sUriMatcher.match(uri);
3136b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        switch (match) {
3137b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov            case CONTACTS_PHOTO:
3138b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                if (!"r".equals(mode)) {
3139b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                    throw new FileNotFoundException("Mode " + mode + " not supported.");
3140b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                }
3141b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3142b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
3143b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3144b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                String sql =
3145b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                        "SELECT " + Photo.PHOTO + " FROM " + mOpenHelper.getDataView() +
3146b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                        " WHERE " + Data._ID + "=" + Contacts.PHOTO_ID
3147b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                                + " AND " + RawContacts.CONTACT_ID + "=" + contactId;
3148b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                SQLiteDatabase db = mOpenHelper.getReadableDatabase();
3149b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                return SQLiteContentHelper.getBlobColumnAsAssetFile(db, sql, null);
3150b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3151b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov            default:
3152b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                throw new FileNotFoundException("No file at: " + uri);
3153b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        }
3154b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    }
3155b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3156b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3157b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3158619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
31597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     * An implementation of EntityIterator that joins the contacts and data tables
31607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     * and consumes all the data rows for a contact in order to build the Entity for a contact.
31617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
31627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    private static class ContactsEntityIterator implements EntityIterator {
31637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private final Cursor mEntityCursor;
31647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private volatile boolean mIsClosed;
31657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
31667e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private static final String[] DATA_KEYS = new String[]{
31677a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA1,
31687a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA2,
31697a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA3,
31707a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA4,
31717a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA5,
31727a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA6,
31737a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA7,
31747a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA8,
31757a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA9,
31767a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA10,
31777a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA11,
31787a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA12,
31797a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA13,
31807a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA14,
31817a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA15,
31827a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC1,
31837a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC2,
31847a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC3,
31857a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC4};
31867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
31877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private static final String[] PROJECTION = new String[]{
31886cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.ACCOUNT_NAME,
31896cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
31906cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.SOURCE_ID,
31916cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.VERSION,
31926cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.DIRTY,
31937a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data._ID,
31947a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.RES_PACKAGE,
31957a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.MIMETYPE,
31967a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA1,
31977a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA2,
31987a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA3,
31997a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA4,
32007a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA5,
32017a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA6,
32027a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA7,
32037a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA8,
32047a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA9,
32057a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA10,
32067a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA11,
32077a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA12,
32087a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA13,
32097a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA14,
32107a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA15,
32117a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC1,
32127a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC2,
32137a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC3,
32147a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC4,
32157a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.RAW_CONTACT_ID,
32167a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.IS_PRIMARY,
32177a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA_VERSION,
32187a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                GroupMembership.GROUP_SOURCE_ID,
32197a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC1,
32207a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC2,
32217a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC3,
322294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                RawContacts.SYNC4,
322338446bf47c5ee2080df69f5fc8a33ad2fa3e61b5Jeff Sharkey                RawContacts.DELETED,
3224c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey                RawContacts.CONTACT_ID,
3225c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey                RawContacts.STARRED};
3226035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana
3227035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_ACCOUNT_NAME = 0;
3228035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_ACCOUNT_TYPE = 1;
3229035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_SOURCE_ID = 2;
3230035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_VERSION = 3;
3231035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_DIRTY = 4;
3232035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_DATA_ID = 5;
323367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_RES_PACKAGE = 6;
323467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_MIMETYPE = 7;
323567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_DATA1 = 8;
32367a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_RAW_CONTACT_ID = 27;
32377a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_IS_PRIMARY = 28;
32387a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_DATA_VERSION = 29;
32397a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_GROUP_SOURCE_ID = 30;
32407a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC1 = 31;
32417a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC2 = 32;
32427a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC3 = 33;
32437a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC4 = 34;
324494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        private static final int COLUMN_DELETED = 35;
324538446bf47c5ee2080df69f5fc8a33ad2fa3e61b5Jeff Sharkey        private static final int COLUMN_CONTACT_ID = 36;
3246c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey        private static final int COLUMN_STARRED = 37;
32477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public ContactsEntityIterator(ContactsProvider2 provider, String contactsIdString, Uri uri,
32497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                String selection, String[] selectionArgs, String sortOrder) {
32507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mIsClosed = false;
32517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final String updatedSortOrder = (sortOrder == null)
32537a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                    ? Data.RAW_CONTACT_ID
32547a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                    : (Data.RAW_CONTACT_ID + "," + sortOrder);
32557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase();
32577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
3258226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setTables(Tables.CONTACT_ENTITIES);
32597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (contactsIdString != null) {
32605ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.appendWhere(Data.RAW_CONTACT_ID + "=" + contactsIdString);
32617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
32626cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
32636cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
3264035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            if (!TextUtils.isEmpty(accountName)) {
32656cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
3266035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                        + DatabaseUtils.sqlEscapeString(accountName) + " AND "
32676cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                        + RawContacts.ACCOUNT_TYPE + "="
3268035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                        + DatabaseUtils.sqlEscapeString(accountType));
3269035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            }
32707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs,
32717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    null, null, updatedSortOrder);
32727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor.moveToFirst();
32737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
32747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
3275038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        public void reset() throws RemoteException {
3276038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            if (mIsClosed) {
3277038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana                throw new IllegalStateException("calling reset() when the iterator is closed");
3278038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            }
3279038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            mEntityCursor.moveToFirst();
3280038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        }
3281038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana
32827e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public void close() {
32837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
32847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("closing when already closed");
32857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
32867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mIsClosed = true;
32877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor.close();
32887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
32897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public boolean hasNext() throws RemoteException {
32917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
32927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("calling hasNext() when the iterator is closed");
32937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
32947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return !mEntityCursor.isAfterLast();
32967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
32977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public Entity next() throws RemoteException {
32997e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
33007e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("calling next() when the iterator is closed");
33017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
33027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (!hasNext()) {
33037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("you may only call next() if hasNext() is true");
33047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
33057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteCursor c = (SQLiteCursor) mEntityCursor;
33077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33087a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            final long rawContactId = c.getLong(COLUMN_RAW_CONTACT_ID);
33097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            // we expect the cursor is already at the row we need to read from
33117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            ContentValues contactValues = new ContentValues();
33126cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME));
33136cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE));
33145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            contactValues.put(RawContacts._ID, rawContactId);
33156cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.DIRTY, c.getLong(COLUMN_DIRTY));
33166cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.VERSION, c.getLong(COLUMN_VERSION));
33176cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.SOURCE_ID, c.getString(COLUMN_SOURCE_ID));
33187a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC1, c.getString(COLUMN_SYNC1));
33197a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC2, c.getString(COLUMN_SYNC2));
33207a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC3, c.getString(COLUMN_SYNC3));
33217a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC4, c.getString(COLUMN_SYNC4));
332294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            contactValues.put(RawContacts.DELETED, c.getLong(COLUMN_DELETED));
332338446bf47c5ee2080df69f5fc8a33ad2fa3e61b5Jeff Sharkey            contactValues.put(RawContacts.CONTACT_ID, c.getLong(COLUMN_CONTACT_ID));
3324c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey            contactValues.put(RawContacts.STARRED, c.getLong(COLUMN_STARRED));
33257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            Entity contact = new Entity(contactValues);
33267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            // read data rows until the contact id changes
33287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            do {
33297a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                if (rawContactId != c.getLong(COLUMN_RAW_CONTACT_ID)) {
33307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    break;
33317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
33327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                // add the data to to the contact
33337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                ContentValues dataValues = new ContentValues();
33347a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data._ID, c.getString(COLUMN_DATA_ID));
33357a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.RES_PACKAGE, c.getString(COLUMN_RES_PACKAGE));
33367a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.MIMETYPE, c.getString(COLUMN_MIMETYPE));
33377a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.IS_PRIMARY, c.getString(COLUMN_IS_PRIMARY));
33387a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION));
33399261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (!c.isNull(COLUMN_GROUP_SOURCE_ID)) {
33409261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    dataValues.put(GroupMembership.GROUP_SOURCE_ID,
33419261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            c.getString(COLUMN_GROUP_SOURCE_ID));
33429261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
33437a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION));
33447a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                for (int i = 0; i < DATA_KEYS.length; i++) {
33457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    final int columnIndex = i + COLUMN_DATA1;
33467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    String key = DATA_KEYS[i];
33477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    if (c.isNull(columnIndex)) {
33487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        // don't put anything
33497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isLong(columnIndex)) {
33507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getLong(columnIndex));
33517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isFloat(columnIndex)) {
33527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getFloat(columnIndex));
33537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isString(columnIndex)) {
33547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getString(columnIndex));
33557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isBlob(columnIndex)) {
33567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getBlob(columnIndex));
33577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    }
33587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
33597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                contact.addSubValue(Data.CONTENT_URI, dataValues);
33607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            } while (mEntityCursor.moveToNext());
33617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return contact;
33637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
33647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
33657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
3366226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    /**
3367226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     * An implementation of EntityIterator that joins the contacts and data tables
3368226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     * and consumes all the data rows for a contact in order to build the Entity for a contact.
3369226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     */
3370226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    private static class GroupsEntityIterator implements EntityIterator {
3371226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private final Cursor mEntityCursor;
3372226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private volatile boolean mIsClosed;
3373226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3374226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final String[] PROJECTION = new String[]{
3375226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups._ID,
3376226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.ACCOUNT_NAME,
3377226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.ACCOUNT_TYPE,
3378226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.SOURCE_ID,
3379226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.DIRTY,
3380226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.VERSION,
3381226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.RES_PACKAGE,
3382226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.TITLE,
3383226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.TITLE_RES,
33847a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.GROUP_VISIBLE,
33857a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC1,
33867a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC2,
33877a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC3,
33887a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC4,
33897a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYSTEM_ID,
339094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                Groups.NOTES,
339194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                Groups.DELETED};
3392226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3393226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ID = 0;
3394226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ACCOUNT_NAME = 1;
3395226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ACCOUNT_TYPE = 2;
3396226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_SOURCE_ID = 3;
3397226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_DIRTY = 4;
3398226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_VERSION = 5;
3399226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_RES_PACKAGE = 6;
3400226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_TITLE = 7;
3401226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_TITLE_RES = 8;
3402226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_GROUP_VISIBLE = 9;
34037a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC1 = 10;
34047a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC2 = 11;
34057a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC3 = 12;
34067a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC4 = 13;
34077a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYSTEM_ID = 14;
34087a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_NOTES = 15;
340994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        private static final int COLUMN_DELETED = 16;
3410226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3411226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public GroupsEntityIterator(ContactsProvider2 provider, String groupIdString, Uri uri,
3412226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                String selection, String[] selectionArgs, String sortOrder) {
3413226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mIsClosed = false;
3414226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3415226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String updatedSortOrder = (sortOrder == null)
3416226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    ? Groups._ID
3417226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    : (Groups._ID + "," + sortOrder);
3418226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3419226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase();
3420226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
3421226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
3422226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setProjectionMap(sGroupsProjectionMap);
3423226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (groupIdString != null) {
3424226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                qb.appendWhere(Groups._ID + "=" + groupIdString);
3425226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3426226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String accountName = uri.getQueryParameter(Groups.ACCOUNT_NAME);
3427226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String accountType = uri.getQueryParameter(Groups.ACCOUNT_TYPE);
3428226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (!TextUtils.isEmpty(accountName)) {
3429226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                qb.appendWhere(Groups.ACCOUNT_NAME + "="
3430226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + DatabaseUtils.sqlEscapeString(accountName) + " AND "
3431226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + Groups.ACCOUNT_TYPE + "="
3432226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + DatabaseUtils.sqlEscapeString(accountType));
3433226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3434226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs,
3435226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    null, null, updatedSortOrder);
3436226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.moveToFirst();
3437226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
3438226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3439226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public void close() {
3440226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
3441226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("closing when already closed");
3442226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3443226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mIsClosed = true;
3444226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.close();
3445226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
3446226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3447226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public boolean hasNext() throws RemoteException {
3448226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
3449226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("calling hasNext() when the iterator is closed");
3450226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3451226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3452226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            return !mEntityCursor.isAfterLast();
3453226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
3454226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3455038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        public void reset() throws RemoteException {
3456038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            if (mIsClosed) {
3457038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana                throw new IllegalStateException("calling reset() when the iterator is closed");
3458038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            }
3459038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            mEntityCursor.moveToFirst();
3460038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        }
3461e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
3462226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public Entity next() throws RemoteException {
3463226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
3464226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("calling next() when the iterator is closed");
3465226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3466226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (!hasNext()) {
3467226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("you may only call next() if hasNext() is true");
3468226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3469226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3470226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteCursor c = (SQLiteCursor) mEntityCursor;
3471226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3472226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final long groupId = c.getLong(COLUMN_ID);
3473226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3474226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            // we expect the cursor is already at the row we need to read from
3475226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            ContentValues groupValues = new ContentValues();
3476226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME));
3477226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE));
3478226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups._ID, groupId);
3479226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.DIRTY, c.getLong(COLUMN_DIRTY));
3480226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.VERSION, c.getLong(COLUMN_VERSION));
3481226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.SOURCE_ID, c.getString(COLUMN_SOURCE_ID));
3482226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.RES_PACKAGE, c.getString(COLUMN_RES_PACKAGE));
3483226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.TITLE, c.getString(COLUMN_TITLE));
3484226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.TITLE_RES, c.getString(COLUMN_TITLE_RES));
3485226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.GROUP_VISIBLE, c.getLong(COLUMN_GROUP_VISIBLE));
34867a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC1, c.getString(COLUMN_SYNC1));
34877a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC2, c.getString(COLUMN_SYNC2));
34887a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC3, c.getString(COLUMN_SYNC3));
34897a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC4, c.getString(COLUMN_SYNC4));
34907a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYSTEM_ID, c.getString(COLUMN_SYSTEM_ID));
349194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            groupValues.put(Groups.DELETED, c.getLong(COLUMN_DELETED));
34927a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.NOTES, c.getString(COLUMN_NOTES));
3493226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            Entity group = new Entity(groupValues);
3494226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3495226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.moveToNext();
3496226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3497226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            return group;
3498226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
3499226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    }
3500226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3501a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    @Override
35027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
35037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            String sortOrder) {
3504568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
3505568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
35067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        final int match = sUriMatcher.match(uri);
35077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        switch (match) {
35085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS:
35095ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID:
35107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                String contactsIdString = null;
35115ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                if (match == RAW_CONTACTS_ID) {
35127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    contactsIdString = uri.getPathSegments().get(1);
35137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
35147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
35157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                return new ContactsEntityIterator(this, contactsIdString,
35167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        uri, selection, selectionArgs, sortOrder);
3517226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            case GROUPS:
3518226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            case GROUPS_ID:
3519226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                String idString = null;
3520226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                if (match == GROUPS_ID) {
3521226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    idString = uri.getPathSegments().get(1);
3522226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                }
3523226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3524226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                return new GroupsEntityIterator(this, idString,
3525226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        uri, selection, selectionArgs, sortOrder);
35267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            default:
35277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new UnsupportedOperationException("Unknown uri: " + uri);
35287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
35297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
35307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
35314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
35324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public String getType(Uri uri) {
3533a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
35344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
3535d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: return Contacts.CONTENT_TYPE;
3536d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: return Contacts.CONTENT_ITEM_TYPE;
35375ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: return RawContacts.CONTENT_TYPE;
35385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: return RawContacts.CONTENT_ITEM_TYPE;
3539508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            case DATA_ID:
35406bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
3541508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey                long dataId = ContentUris.parseId(uri);
3542b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                return mOpenHelper.getDataMimeType(dataId);
354331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_EXCEPTIONS: return AggregationExceptions.CONTENT_TYPE;
354431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_EXCEPTION_ID: return AggregationExceptions.CONTENT_ITEM_TYPE;
3545eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: return Settings.CONTENT_TYPE;
3546d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case AGGREGATION_SUGGESTIONS: return Contacts.CONTENT_TYPE;
3547c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS:
3548c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SUGGEST_MIME_TYPE;
3549c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT:
3550c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SHORTCUT_MIME_TYPE;
355161efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov            default:
355261efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov                return mLegacyApiSupport.getType(uri);
35534f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
35544f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
35557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
35565ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private void setDisplayName(long rawContactId, String displayName) {
35573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (displayName != null) {
35583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mContactDisplayNameUpdate.bindString(1, displayName);
35593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        } else {
35603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mContactDisplayNameUpdate.bindNull(1);
35613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
35625ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mContactDisplayNameUpdate.bindLong(2, rawContactId);
35633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mContactDisplayNameUpdate.execute();
35643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
35653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
356673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /**
356773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Checks the {@link Data#MARK_AS_DIRTY} query parameter.
356873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     *
356973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Returns true if the parameter is missing or is either "true" or "1".
357073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     */
357173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private boolean shouldMarkRawContactAsDirty(Uri uri) {
357273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (mImportMode) {
357373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            return false;
357473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
357573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
357673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        String param = uri.getQueryParameter(Data.MARK_AS_DIRTY);
357773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        return param == null || (!param.equalsIgnoreCase("false") && !param.equals("0"));
357873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    }
357973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
358073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /**
358173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Sets the {@link RawContacts#DIRTY} for the specified raw contact.
358273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     */
358373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private void setRawContactDirty(long rawContactId) {
358473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate.bindLong(1, rawContactId);
358573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate.execute();
358673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    }
358773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
358873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /**
358973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Checks the {@link Groups#MARK_AS_DIRTY} query parameter.
359073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     *
359173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Returns true if the parameter is missing or is either "true" or "1".
359273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     */
359373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private boolean shouldMarkGroupAsDirty(Uri uri) {
359473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (mImportMode) {
359573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            return false;
359673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
359773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
35982971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana        return readBooleanQueryParameter(uri, Groups.MARK_AS_DIRTY, true);
359973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    }
360073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
3601c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
3602c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to primary, and resets all data records of
3603c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * the same mimetype and under the same contact to not be primary.
3604c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
3605c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
3606c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
3607653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    private void setIsPrimary(long rawContactId, long dataId, long mimeTypeId) {
3608c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.bindLong(1, dataId);
3609653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetPrimaryStatement.bindLong(2, mimeTypeId);
3610653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetPrimaryStatement.bindLong(3, rawContactId);
3611c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.execute();
3612c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
3613c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
3614c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
3615c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to "super primary", and resets all data
3616c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * records of the same mimetype and under the same aggregate to not be "super primary".
3617c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
3618c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
3619c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
3620653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    private void setIsSuperPrimary(long rawContactId, long dataId, long mimeTypeId) {
3621c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.bindLong(1, dataId);
3622653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetSuperPrimaryStatement.bindLong(2, mimeTypeId);
3623653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetSuperPrimaryStatement.bindLong(3, rawContactId);
3624c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.execute();
3625c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
3626ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
3627e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    private void appendContactByFilterAsNestedQuery(StringBuilder sb, String filterParam) {
3628e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        sb.append("(SELECT DISTINCT " + RawContacts.CONTACT_ID + " FROM " + Tables.RAW_CONTACTS
3629e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                + " JOIN name_lookup ON(" + RawContactsColumns.CONCRETE_ID + "=raw_contact_id)"
3630e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                + " WHERE normalized_name GLOB '");
3631e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        sb.append(NameNormalizer.normalize(filterParam));
3632e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        sb.append("*')");
3633e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    }
3634e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
36355ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public String getRawContactsByFilterAsNestedQuery(String filterParam) {
3636c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        StringBuilder sb = new StringBuilder();
3637c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        appendRawContactsByFilterAsNestedQuery(sb, filterParam, null);
3638c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        return sb.toString();
3639c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
3640c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
3641a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    public void appendRawContactsByFilterAsNestedQuery(StringBuilder sb, String filterParam,
3642c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            String limit) {
3643c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append("(SELECT DISTINCT raw_contact_id FROM name_lookup WHERE normalized_name GLOB '");
3644c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append(NameNormalizer.normalize(filterParam));
3645c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append("*'");
3646c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limit != null) {
3647c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            sb.append(" LIMIT ").append(limit);
3648c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
3649c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append(")");
3650ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    }
3651ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
36524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /**
36534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     * Inserts an argument at the beginning of the selection arg list.
36544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     */
36554a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private String[] insertSelectionArg(String[] selectionArgs, String arg) {
3656b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        if (selectionArgs == null) {
3657b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return new String[] {arg};
3658b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        } else {
3659b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            int newLength = selectionArgs.length + 1;
3660b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            String[] newSelectionArgs = new String[newLength];
36614a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            newSelectionArgs[0] = arg;
36624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length);
3663b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return newSelectionArgs;
3664b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        }
3665b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    }
3666caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
3667caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    protected Account getDefaultAccount() {
3668caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        AccountManager accountManager = AccountManager.get(getContext());
3669caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        try {
3670df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana            Account[] accounts = accountManager.getAccountsByTypeAndFeatures(DEFAULT_ACCOUNT_TYPE,
3671df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                    new String[] {FEATURE_LEGACY_HOSTED_OR_GOOGLE}, null, null).getResult();
3672caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            if (accounts != null && accounts.length > 0) {
3673caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov                return accounts[0];
3674caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            }
3675caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        } catch (Throwable e) {
36766f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov            Log.e(TAG, "Cannot determine the default account for contacts compatibility", e);
3677caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        }
36786f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov        return null;
3679caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    }
36804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton}
3681