ContactsProvider2.java revision 3cb415e7b97c3e318d7a16aaf7cc5c6b825d349a
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;
2625abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.DisplayNameSources;
2728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.GroupsColumns;
2828f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.MimetypesColumns;
2911944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.NameLookupColumns;
305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.NameLookupType;
3167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport com.android.providers.contacts.OpenHelper.PackagesColumns;
32d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.PhoneColumns;
3328f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.PhoneLookupColumns;
344dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikovimport com.android.providers.contacts.OpenHelper.PresenceColumns;
35d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.RawContactsColumns;
3628f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.Tables;
37e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikovimport com.google.android.collect.Lists;
38e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
39b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account;
40caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikovimport android.accounts.AccountManager;
41c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager;
42568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderOperation;
43568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderResult;
4435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris;
4567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues;
4667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context;
4735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.Entity;
4867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.EntityIterator;
49568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.OperationApplicationException;
503d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences;
5167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher;
523d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences.Editor;
53b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.content.res.AssetFileDescriptor;
544f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor;
55ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils;
56b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.database.sqlite.SQLiteContentHelper;
57b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.database.sqlite.SQLiteCursor;
584f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase;
594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder;
60c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millarimport android.database.sqlite.SQLiteStatement;
614f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri;
62b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException;
633d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager;
64508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns;
65de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract;
661b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikovimport android.provider.LiveFolders;
67b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions;
68de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds;
69d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
70de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Data;
71ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.Groups;
72e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikovimport android.provider.ContactsContract.PhoneLookup;
731f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkeyimport android.provider.ContactsContract.Presence;
74d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
75eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkeyimport android.provider.ContactsContract.Settings;
763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.BaseTypes;
77ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Email;
78ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im;
803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname;
813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization;
82de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds.Phone;
83b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Photo;
844097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
8567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
86a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils;
87a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils;
88c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log;
894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
90b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport java.io.FileNotFoundException;
917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList;
925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.Collections;
93b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap;
945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.List;
95ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch;
964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/**
984f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications
994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}.
1004f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */
101de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikovpublic class ContactsProvider2 extends SQLiteContentProvider {
102caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
103b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    // TODO: clean up debug tag and rename this class
104b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private static final String TAG = "ContactsProvider ~~~~";
1054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
106619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: carefully prevent all incoming nested queries; they can be gaping security holes
107619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: check for restricted flag during insert(), update(), and delete() calls
108619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
1093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Default for the maximum number of returned aggregation suggestions. */
1103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DEFAULT_MAX_SUGGESTIONS = 5;
1113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1123d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /**
1133d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * Shared preference key for the legacy contact import version. The need for a version
1143d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * as opposed to a boolean flag is that if we discover bugs in the contact import process,
1153d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * we can trigger re-import by incrementing the import version.
1163d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     */
1173d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private static final String PREF_CONTACTS_IMPORTED = "contacts_imported_v1";
1183d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private static final int PREF_CONTACTS_IMPORT_VERSION = 1;
1193d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
120a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
1214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
122d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, "
123d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.TIMES_CONTACTED + " DESC, "
124d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.DISPLAY_NAME + " ASC";
125d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar    private static final String STREQUENT_LIMIT =
126d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE "
127d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.STARRED + "=1) + 25";
128d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov
129d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS = 1000;
130d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS_ID = 1001;
1315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_LOOKUP = 1002;
1325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_LOOKUP_ID = 1003;
1335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_DATA = 1004;
1345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_FILTER = 1005;
1355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_STREQUENT = 1006;
1365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_STREQUENT_FILTER = 1007;
1375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_GROUP = 1008;
1385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_PHOTO = 1009;
1394f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1405ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS = 2002;
1415ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_ID = 2003;
1425ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_DATA = 2004;
1434f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1446bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA = 3000;
1456bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA_ID = 3001;
146ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int PHONES = 3002;
147ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int PHONES_FILTER = 3003;
1484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final int EMAILS = 3004;
1494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final int EMAILS_FILTER = 3005;
1504a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final int POSTALS = 3006;
151a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1526bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int PHONE_LOOKUP = 4000;
1536bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
154b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTIONS = 6000;
155b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTION_ID = 6001;
156b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
1571f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    private static final int PRESENCE = 7000;
1581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    private static final int PRESENCE_ID = 7001;
1591f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
16031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    private static final int AGGREGATION_SUGGESTIONS = 8000;
16131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
162eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    private static final int SETTINGS = 9000;
163eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
164ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS = 10000;
165ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_ID = 10001;
166ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_SUMMARY = 10003;
167ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
16835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana    private static final int SYNCSTATE = 11000;
16935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
170c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SUGGESTIONS = 12001;
171c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SHORTCUT = 12002;
172c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
173a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov    private static final int DATA_WITH_PRESENCE = 13000;
17419a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
1751b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS = 14000;
1761b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_WITH_PHONES = 14001;
1771b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002;
1781b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003;
1791b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
18067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    private interface ContactsQuery {
1815ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final String TABLE = Tables.RAW_CONTACTS;
1829261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
18367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
1846cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
1856cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.ACCOUNT_NAME,
1866cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.ACCOUNT_TYPE,
187ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
188ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1895ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
19067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int ACCOUNT_NAME = 1;
19167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int ACCOUNT_TYPE = 2;
19267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    }
19367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
194d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private interface DataContactsQuery {
195d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS;
19667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
19767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
1986cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
1993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
200d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            ContactsColumns.CONCRETE_ID,
2013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.CONCRETE_ID,
202ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
203ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
204d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
20567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA_ID = 1;
206d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int CONTACT_ID = 2;
20767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int MIMETYPE_ID = 3;
208ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
2091f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private interface DisplayNameQuery {
21167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
2123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final String[] COLUMNS = new String[] {
2143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
2153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
2163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA2,
2173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            StructuredName.DISPLAY_NAME,
2183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
2193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 0;
2213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 1;
2223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA2 = 2;
2233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DISPLAY_NAME = 3;
2243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
2253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
22614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    private interface DataDeleteQuery {
22767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
2283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
22988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] CONCRETE_COLUMNS = new String[] {
2303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
2313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
2325ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Data.RAW_CONTACT_ID,
2333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
2343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA2,
23588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        };
23688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov
23788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] COLUMNS = new String[] {
23888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data._ID,
23988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            MimetypesColumns.MIMETYPE,
24088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.RAW_CONTACT_ID,
24188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.IS_PRIMARY,
24288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.DATA2,
2433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
2443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
24514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public static final int _ID = 0;
2463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 1;
2475ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 2;
2483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 3;
24988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final int DATA2 = 4;
2503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
2513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
25214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    private interface DataUpdateQuery {
253321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        String[] COLUMNS = { Data._ID, Data.RAW_CONTACT_ID, Data.MIMETYPE };
25420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
25520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int _ID = 0;
256321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int RAW_CONTACT_ID = 1;
257321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int MIMETYPE = 2;
25820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
25920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
26025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov    private static final HashMap<String, Integer> sDisplayNameSources;
2613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    static {
26225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        sDisplayNameSources = new HashMap<String, Integer>();
26325abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        sDisplayNameSources.put(StructuredName.CONTENT_ITEM_TYPE,
26425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                DisplayNameSources.STRUCTURED_NAME);
26525abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        sDisplayNameSources.put(Organization.CONTENT_ITEM_TYPE,
26625abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                DisplayNameSources.ORGANIZATION);
26725abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        sDisplayNameSources.put(Phone.CONTENT_ITEM_TYPE,
26825abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                DisplayNameSources.PHONE);
26925abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        sDisplayNameSources.put(Email.CONTENT_ITEM_TYPE,
27025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                DisplayNameSources.EMAIL);
2713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
27231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
273caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    public static final String DEFAULT_ACCOUNT_TYPE = "com.google.GAIA";
274df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana    public static final String FEATURE_LEGACY_HOSTED_OR_GOOGLE = "legacy_hosted_or_google";
275caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
276038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana    /** Contains just BaseColumns._COUNT */
277038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana    private static final HashMap<String, String> sCountProjectionMap;
278e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov    /** Contains just the contacts columns */
2794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    private static final HashMap<String, String> sContactsProjectionMap;
280ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    /** Contains contacts and presence columns */
281ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    private static final HashMap<String, String> sContactsWithPresenceProjectionMap;
282ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    /** Contains just the raw contacts columns */
283d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final HashMap<String, String> sRawContactsProjectionMap;
2844a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /** Contains columns from the data view */
2854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final HashMap<String, String> sDataProjectionMap;
2869261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /** Contains the data and contacts columns, for joined tables */
287e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov    private static final HashMap<String, String> sPhoneLookupProjectionMap;
288ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains the just the {@link Groups} columns */
289ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsProjectionMap;
290ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains {@link Groups} columns along with summary details */
291ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsSummaryProjectionMap;
292373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    /** Contains the agg_exceptions columns */
293b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final HashMap<String, String> sAggregationExceptionsProjectionMap;
294eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    /** Contains the agg_exceptions columns */
295eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    private static final HashMap<String, String> sSettingsProjectionMap;
296373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    /** Contains Presence columns */
297373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    private static final HashMap<String, String> sPresenceProjectionMap;
29819a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov    /** Contains Presence columns */
299a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov    private static final HashMap<String, String> sDataWithPresenceProjectionMap;
3001b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    /** Contains Live Folders columns */
3011b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final HashMap<String, String> sLiveFoldersProjectionMap;
3027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
303b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    /** Sql where statement for filtering on groups. */
304d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String sContactsInGroupSelect;
30519a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
306c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Precompiled sql statement for setting a data record to the primary. */
307c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetPrimaryStatement;
3083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for setting a data record to the super primary. */
309c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetSuperPrimaryStatement;
310d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Precompiled sql statement for incrementing times contacted for an contact */
311f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private SQLiteStatement mLastTimeContactedUpdate;
3123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for updating a contact display name */
31325abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov    private SQLiteStatement mRawContactDisplayNameUpdate;
31473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /** Precompiled sql statement for marking a raw contact as dirty */
31573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private SQLiteStatement mRawContactDirtyUpdate;
316e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    /** Precompiled sql statement for setting an aggregated presence */
317e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    private SQLiteStatement mAggregatedPresenceReplace;
318e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    /** Precompiled sql statement for updating an aggregated presence status */
319e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    private SQLiteStatement mAggregatedPresenceStatusUpdate;
320a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
3214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    static {
3224f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        // Contacts URI matching table
323a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final UriMatcher matcher = sUriMatcher;
324d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS);
325d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
326d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_DATA);
3273653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions",
3283653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                AGGREGATION_SUGGESTIONS);
3293653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_PHOTO);
3305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER);
3315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP);
3325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID);
3335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT);
334ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*",
335ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                CONTACTS_STREQUENT_FILTER);
3365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP);
3373653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
3385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
3395ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID);
3405ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA);
341b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
3424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);
3434f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID);
344ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES);
345ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER);
3464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS);
3474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER);
348ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS);
3491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
350ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS);
351ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID);
352ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY);
353ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
35435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE);
35535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
356a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP);
357b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions",
358b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTIONS);
359b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*",
360b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTION_ID);
3614f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
362eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS);
363eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
364bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "presence", PRESENCE);
365bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "presence/#", PRESENCE_ID);
3661f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
367c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
368c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
369c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
370c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
371c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/#",
372c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SHORTCUT);
373c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
3741b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts",
3751b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS);
3761b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*",
3771b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_GROUP_NAME);
3781b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones",
3791b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_WITH_PHONES);
3801b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites",
3811b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_FAVORITES);
3821b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
38319a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov        // Private API
384a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data_with_presence", DATA_WITH_PRESENCE);
38519a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov    }
38619a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
38719a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov    static {
388038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        sCountProjectionMap = new HashMap<String, String>();
389038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        sCountProjectionMap.put(BaseColumns._COUNT, "COUNT(*)");
390e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
3914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap = new HashMap<String, String>();
3924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts._ID, Contacts._ID);
3934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME);
3944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
3954a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
3964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
3974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.IN_VISIBLE_GROUP, Contacts.IN_VISIBLE_GROUP);
3984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
3994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
400f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov        sContactsProjectionMap.put(Contacts.HAS_PHONE_NUMBER, Contacts.HAS_PHONE_NUMBER);
4014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
4025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sContactsProjectionMap.put(Contacts.LOOKUP_KEY, Contacts.LOOKUP_KEY);
4034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
404ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        sContactsWithPresenceProjectionMap = new HashMap<String, String>();
405ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        sContactsWithPresenceProjectionMap.putAll(sContactsProjectionMap);
406ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        sContactsWithPresenceProjectionMap.put(Contacts.PRESENCE_STATUS,
407e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                Presence.PRESENCE_STATUS + " AS " + Contacts.PRESENCE_STATUS);
408ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        sContactsWithPresenceProjectionMap.put(Contacts.PRESENCE_CUSTOM_STATUS,
409ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                Presence.PRESENCE_CUSTOM_STATUS + " AS " + Contacts.PRESENCE_CUSTOM_STATUS);
4104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
4114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap = new HashMap<String, String>();
4124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts._ID, RawContacts._ID);
4134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
4144a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
4154a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
4164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
4174a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.VERSION, RawContacts.VERSION);
4184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DIRTY, RawContacts.DIRTY);
4194a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DELETED, RawContacts.DELETED);
4204a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.TIMES_CONTACTED, RawContacts.TIMES_CONTACTED);
4214a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.LAST_TIME_CONTACTED,
4224a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                RawContacts.LAST_TIME_CONTACTED);
4234a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.CUSTOM_RINGTONE, RawContacts.CUSTOM_RINGTONE);
4244a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SEND_TO_VOICEMAIL, RawContacts.SEND_TO_VOICEMAIL);
4254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.STARRED, RawContacts.STARRED);
4264a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE);
4274a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC1, RawContacts.SYNC1);
4284a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC2, RawContacts.SYNC2);
4294a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC3, RawContacts.SYNC3);
4304a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC4, RawContacts.SYNC4);
4312815f58f72f109790585931f601a63ddc02536a5Evan Millar
4324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap = new HashMap<String, String>();
4334a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data._ID, Data._ID);
4344a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.RAW_CONTACT_ID, Data.RAW_CONTACT_ID);
4354a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA_VERSION, Data.DATA_VERSION);
4364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.IS_PRIMARY, Data.IS_PRIMARY);
4374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY);
4384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.RES_PACKAGE, Data.RES_PACKAGE);
4394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.MIMETYPE, Data.MIMETYPE);
4404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA1, Data.DATA1);
4414a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA2, Data.DATA2);
4424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA3, Data.DATA3);
4434a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA4, Data.DATA4);
4444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA5, Data.DATA5);
4454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA6, Data.DATA6);
4464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA7, Data.DATA7);
4474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA8, Data.DATA8);
4484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA9, Data.DATA9);
4494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA10, Data.DATA10);
4504a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA11, Data.DATA11);
4514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA12, Data.DATA12);
4524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA13, Data.DATA13);
4534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA14, Data.DATA14);
4544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA15, Data.DATA15);
4554a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC1, Data.SYNC1);
4564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC2, Data.SYNC2);
4574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC3, Data.SYNC3);
4584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC4, Data.SYNC4);
4594a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
4604a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
4614a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
4624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
4634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.VERSION, RawContacts.VERSION);
4644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.DIRTY, RawContacts.DIRTY);
4654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME);
4664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
4674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
4684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
4694a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
4704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
4714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
4724a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(GroupMembership.GROUP_SOURCE_ID, GroupMembership.GROUP_SOURCE_ID);
473a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
474e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap = new HashMap<String, String>();
475e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup._ID,
476e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_ID + " AS " + PhoneLookup._ID);
477e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.DISPLAY_NAME,
478e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_DISPLAY_NAME + " AS " + PhoneLookup.DISPLAY_NAME);
479e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.LAST_TIME_CONTACTED,
480e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_LAST_TIME_CONTACTED
481e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                        + " AS " + PhoneLookup.LAST_TIME_CONTACTED);
482e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.TIMES_CONTACTED,
483e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_TIMES_CONTACTED + " AS " + PhoneLookup.TIMES_CONTACTED);
484e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.STARRED,
485e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_STARRED + " AS " + PhoneLookup.STARRED);
486e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.IN_VISIBLE_GROUP,
487e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Contacts.IN_VISIBLE_GROUP + " AS " + PhoneLookup.IN_VISIBLE_GROUP);
488e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.PHOTO_ID,
489e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Contacts.PHOTO_ID + " AS " + PhoneLookup.PHOTO_ID);
490e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.CUSTOM_RINGTONE,
491e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_CUSTOM_RINGTONE + " AS " + PhoneLookup.CUSTOM_RINGTONE);
492e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.HAS_PHONE_NUMBER,
493e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Contacts.HAS_PHONE_NUMBER + " AS " + PhoneLookup.HAS_PHONE_NUMBER);
494e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.SEND_TO_VOICEMAIL,
495e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                ContactsColumns.CONCRETE_SEND_TO_VOICEMAIL
496e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                        + " AS " + PhoneLookup.SEND_TO_VOICEMAIL);
497e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.NUMBER,
498e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.NUMBER + " AS " + PhoneLookup.NUMBER);
499e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.TYPE,
500e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.TYPE + " AS " + PhoneLookup.TYPE);
501e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        sPhoneLookupProjectionMap.put(PhoneLookup.LABEL,
502e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                Phone.LABEL + " AS " + PhoneLookup.LABEL);
5039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
504e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov        HashMap<String, String> columns;
5057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
506ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Groups projection map
507ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
508ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups._ID, "groups._id AS _id");
509035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_NAME, Groups.ACCOUNT_NAME);
510035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_TYPE, Groups.ACCOUNT_TYPE);
5119261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.SOURCE_ID, Groups.SOURCE_ID);
5129261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.DIRTY, Groups.DIRTY);
5139261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.VERSION, Groups.VERSION);
51467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Groups.RES_PACKAGE, PackagesColumns.PACKAGE + " AS " + Groups.RES_PACKAGE);
515ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.TITLE, Groups.TITLE);
51667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Groups.TITLE_RES, Groups.TITLE_RES);
517ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.GROUP_VISIBLE, Groups.GROUP_VISIBLE);
5183cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYSTEM_ID, Groups.SYSTEM_ID);
51994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        columns.put(Groups.DELETED, Groups.DELETED);
5203cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.NOTES, Groups.NOTES);
52138446bf47c5ee2080df69f5fc8a33ad2fa3e61b5Jeff Sharkey        columns.put(Groups.SHOULD_SYNC, Groups.SHOULD_SYNC);
5223cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC1, Tables.GROUPS + "." + Groups.SYNC1 + " AS " + Groups.SYNC1);
5233cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC2, Tables.GROUPS + "." + Groups.SYNC2 + " AS " + Groups.SYNC2);
5243cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC3, Tables.GROUPS + "." + Groups.SYNC3 + " AS " + Groups.SYNC3);
5253cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC4, Tables.GROUPS + "." + Groups.SYNC4 + " AS " + Groups.SYNC4);
526ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsProjectionMap = columns;
527ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
5286cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        // RawContacts and groups projection map
529ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
530ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.putAll(sGroupsProjectionMap);
531d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Groups.SUMMARY_COUNT, "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID
532d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
533ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
534ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + ") AS " + Groups.SUMMARY_COUNT);
535ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.SUMMARY_WITH_PHONES, "(SELECT COUNT(DISTINCT "
536d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ContactsColumns.CONCRETE_ID + ") FROM "
537d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
538ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
539f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov                + " AND " + Contacts.HAS_PHONE_NUMBER + ") AS " + Groups.SUMMARY_WITH_PHONES);
540ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsSummaryProjectionMap = columns;
541ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
542b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        // Aggregate exception projection map
543b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns = new HashMap<String, String>();
544b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id AS _id");
545b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE);
546d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(AggregationExceptions.CONTACT_ID,
547d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                "raw_contacts1." + RawContacts.CONTACT_ID
548d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " AS " + AggregationExceptions.CONTACT_ID);
5495ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        columns.put(AggregationExceptions.RAW_CONTACT_ID, AggregationExceptionColumns.RAW_CONTACT_ID2);
550b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        sAggregationExceptionsProjectionMap = columns;
551b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
552eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        // Settings projection map
553eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns = new HashMap<String, String>();
554eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.ACCOUNT_NAME, Settings.ACCOUNT_NAME);
555eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.ACCOUNT_TYPE, Settings.ACCOUNT_TYPE);
556eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.UNGROUPED_VISIBLE, Settings.UNGROUPED_VISIBLE);
557eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        columns.put(Settings.SHOULD_SYNC, Settings.SHOULD_SYNC);
55868936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey        columns.put(Settings.UNGROUPED_COUNT, "(SELECT COUNT(*) FROM (SELECT 1 FROM "
55968936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS + " GROUP BY "
56068936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID + " HAVING " + Clauses.HAVING_NO_GROUPS
56168936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + ")) AS " + Settings.UNGROUPED_COUNT);
56268936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey        columns.put(Settings.UNGROUPED_WITH_PHONES, "(SELECT COUNT(*) FROM (SELECT 1 FROM "
563e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS + " WHERE "
56468936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Contacts.HAS_PHONE_NUMBER + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID
56568936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + " HAVING " + Clauses.HAVING_NO_GROUPS + ")) AS "
56668936cefd4caa779169ea00ffd1adc399e634c9bJeff Sharkey                + Settings.UNGROUPED_WITH_PHONES);
567eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        sSettingsProjectionMap = columns;
568eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
569373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns = new HashMap<String, String>();
570373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence._ID, Presence._ID);
5714dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        columns.put(PresenceColumns.RAW_CONTACT_ID, PresenceColumns.RAW_CONTACT_ID);
572373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.DATA_ID, Presence.DATA_ID);
573373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.IM_ACCOUNT, Presence.IM_ACCOUNT);
574373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.IM_HANDLE, Presence.IM_HANDLE);
5754dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        columns.put(Presence.PROTOCOL, Presence.PROTOCOL);
5764dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        columns.put(Presence.CUSTOM_PROTOCOL, Presence.CUSTOM_PROTOCOL);
577373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.PRESENCE_STATUS, Presence.PRESENCE_STATUS);
578373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.PRESENCE_CUSTOM_STATUS, Presence.PRESENCE_CUSTOM_STATUS);
579373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        sPresenceProjectionMap = columns;
580373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov
581a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov        sDataWithPresenceProjectionMap = new HashMap<String, String>();
582a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov        sDataWithPresenceProjectionMap.putAll(sDataProjectionMap);
583a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov        sDataWithPresenceProjectionMap.put(Presence.PRESENCE_STATUS,
584e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                Presence.PRESENCE_STATUS);
585a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov        sDataWithPresenceProjectionMap.put(Presence.PRESENCE_CUSTOM_STATUS,
586e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                Presence.PRESENCE_CUSTOM_STATUS);
58719a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
5881b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // Live folder projection
5891b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap = new HashMap<String, String>();
5901b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap.put(LiveFolders._ID,
5911b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                Contacts._ID + " AS " + LiveFolders._ID);
5921b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        sLiveFoldersProjectionMap.put(LiveFolders.NAME,
5931b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                Contacts.DISPLAY_NAME + " AS " + LiveFolders.NAME);
5941b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
5951b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // TODO: Put contact photo back when we have a way to display a default icon
5961b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // for contacts without a photo
5971b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        // sLiveFoldersProjectionMap.put(LiveFolders.ICON_BITMAP,
5981b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        //      Photos.DATA + " AS " + LiveFolders.ICON_BITMAP);
5991b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
6004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsInGroupSelect = Contacts._ID + " IN "
6014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                + "(SELECT " + RawContacts.CONTACT_ID
6024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                + " FROM " + Tables.RAW_CONTACTS
6034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN "
6044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID
6054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        + " FROM " + Tables.DATA_JOIN_MIMETYPES
6064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE
6074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + "' AND " + GroupMembership.GROUP_ROW_ID + "="
6084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + "(SELECT " + Tables.GROUPS + "." + Groups._ID
6094a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + " FROM " + Tables.GROUPS
6104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + " WHERE " + Groups.TITLE + "=?)))";
6114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
6124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
6133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /**
6143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     * Handles inserts and update for a specific Data type.
6153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     */
6163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private abstract class DataRowHandler {
6173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected final String mMimetype;
619653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        protected long mMimetypeId;
6203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public DataRowHandler(String mimetype) {
6223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mMimetype = mimetype;
6233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
625653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        protected long getMimeTypeId() {
626653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (mMimetypeId == 0) {
627653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                mMimetypeId = mOpenHelper.getMimeTypeId(mMimetype);
628653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
629653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return mMimetypeId;
630653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
631653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
6323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
6333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Inserts a row into the {@link Data} table.
6343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
6355ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
636e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            final long dataId = db.insert(Tables.DATA, null, values);
637e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
638e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            Integer primary = values.getAsInteger(Data.IS_PRIMARY);
639e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (primary != null && primary != 0) {
640653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, getMimeTypeId());
641e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
642e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
643e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return dataId;
6443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
6473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Validates data and updates a {@link Data} row using the cursor, which contains
6483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * the current data.
6493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
650653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
651653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                boolean markRawContactAsDirty) {
65214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
65314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
654653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
655653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (values.containsKey(Data.IS_SUPER_PRIMARY)) {
656653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                long mimeTypeId = getMimeTypeId();
657653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
658653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, mimeTypeId);
659653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
660653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                // Now that we've taken care of setting these, remove them from "values".
661653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_SUPER_PRIMARY);
662653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_PRIMARY);
663653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            } else if (values.containsKey(Data.IS_PRIMARY)) {
664653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setIsPrimary(rawContactId, dataId, getMimeTypeId());
665653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
666653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                // Now that we've taken care of setting this, remove it from "values".
667653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(Data.IS_PRIMARY);
668653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
669653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
670653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (values.size() > 0) {
671653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                mDb.update(Tables.DATA, values, Data._ID + " = " + dataId, null);
672653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
673653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
674653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (markRawContactAsDirty) {
675653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                setRawContactDirty(rawContactId);
676653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
6773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
68014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
68114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
68214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            boolean primary = c.getInt(DataDeleteQuery.IS_PRIMARY) != 0;
6833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            int count = db.delete(Tables.DATA, Data._ID + "=" + dataId, null);
6843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (count != 0 && primary) {
6855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                fixPrimary(db, rawContactId);
6863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
6873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return count;
6883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6905ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        private void fixPrimary(SQLiteDatabase db, long rawContactId) {
6915ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long newPrimaryId = findNewPrimaryDataId(db, rawContactId);
6923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (newPrimaryId != -1) {
69314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                setIsPrimary(rawContactId, newPrimaryId, getMimeTypeId());
6943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
6953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6975ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected long findNewPrimaryDataId(SQLiteDatabase db, long rawContactId) {
698e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            long primaryId = -1;
699e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            int primaryType = -1;
7005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Cursor c = queryData(db, rawContactId);
7013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
702e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                while (c.moveToNext()) {
70314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    long dataId = c.getLong(DataDeleteQuery._ID);
70414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    int type = c.getInt(DataDeleteQuery.DATA2);
705e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) {
706e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryId = dataId;
707e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryType = type;
708e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    }
7093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
7103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
7113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
7123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
713e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return primaryId;
714e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
715e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
716e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        /**
717e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * Returns the rank of a specific record type to be used in determining the primary
718e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * row. Lower number represents higher priority.
719e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         */
720e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
721e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return 0;
7223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7245ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected Cursor queryData(SQLiteDatabase db, long rawContactId) {
72514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return db.query(DataDeleteQuery.TABLE, DataDeleteQuery.CONCRETE_COLUMNS,
72614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    Data.RAW_CONTACT_ID + "=" + rawContactId +
72714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    " AND " + MimetypesColumns.MIMETYPE + "='" + mMimetype + "'",
7283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    null, null, null, null);
7293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
73125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        protected void fixRawContactDisplayName(SQLiteDatabase db, long rawContactId) {
7323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String bestDisplayName = null;
73325abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            int bestDisplayNameSource = DisplayNameSources.UNDEFINED;
73425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov
73567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            Cursor c = db.query(DisplayNameQuery.TABLE, DisplayNameQuery.COLUMNS,
7365ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    Data.RAW_CONTACT_ID + "=" + rawContactId, null, null, null, null);
7373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
7383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                while (c.moveToNext()) {
7393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    String mimeType = c.getString(DisplayNameQuery.MIMETYPE);
7403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    boolean primary;
7413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    String name;
7423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
7443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        name = c.getString(DisplayNameQuery.DISPLAY_NAME);
7453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        primary = true;
7463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    } else {
7473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        name = c.getString(DisplayNameQuery.DATA2);
7483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        primary = (c.getInt(DisplayNameQuery.IS_PRIMARY) != 0);
7493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    }
7503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    if (primary && name != null) {
75225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                        Integer source = sDisplayNameSources.get(mimeType);
75325abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                        if (source != null && source > bestDisplayNameSource) {
75425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                            bestDisplayNameSource = source;
7553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                            bestDisplayName = name;
7563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        }
7573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    }
7583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
7593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
7613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
7623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
7633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
76425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            setDisplayName(rawContactId, bestDisplayName, bestDisplayNameSource);
765285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            if (!isNewRawContact(rawContactId)) {
766285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateDisplayName(db, rawContactId);
767285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
7683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
769a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
770a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
771a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return true;
772a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
7733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
7743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CustomDataRowHandler extends DataRowHandler {
7763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CustomDataRowHandler(String mimetype) {
7783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
7793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
7813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class StructuredNameRowHandler extends DataRowHandler {
7833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final NameSplitter mNameSplitter;
7853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public StructuredNameRowHandler(NameSplitter nameSplitter) {
7873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(StructuredName.CONTENT_ITEM_TYPE);
7883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mNameSplitter = nameSplitter;
7893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
7925ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
7933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            fixStructuredNameComponents(values);
79414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
79514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
79614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
79714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String givenName = values.getAsString(StructuredName.GIVEN_NAME);
79814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String familyName = values.getAsString(StructuredName.FAMILY_NAME);
79914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.insertNameLookupForStructuredName(rawContactId, dataId, givenName,
80014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    familyName);
80125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
80214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
80314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
80414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
80514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
80614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
80714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                boolean markRawContactAsDirty) {
808cabac02a2416b495e030654accffcbb5ae526678Dmitri Plotnikov
809cabac02a2416b495e030654accffcbb5ae526678Dmitri Plotnikov            fixStructuredNameComponents(values);
810cabac02a2416b495e030654accffcbb5ae526678Dmitri Plotnikov
81114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
81214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
81314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
81414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super.update(db, values, c, markRawContactAsDirty);
81514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
81614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            boolean hasGivenName = values.containsKey(StructuredName.GIVEN_NAME);
81714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            boolean hasFamilyName = values.containsKey(StructuredName.FAMILY_NAME);
81814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            if  (hasGivenName || hasFamilyName) {
81914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                String givenName;
82014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                String familyName;// = values.getAsString(StructuredName.FAMILY_NAME);
82114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                if (hasGivenName) {
82214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    givenName = values.getAsString(StructuredName.GIVEN_NAME);
82314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                } else {
82414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
82514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    // TODO compiled statement
82614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    givenName = DatabaseUtils.stringForQuery(db,
82714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            "SELECT " + StructuredName.GIVEN_NAME +
82814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            " FROM " + Tables.DATA +
82914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            " WHERE " + Data._ID + "=" + dataId, null);
83014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                }
83114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                if (hasFamilyName) {
83214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    familyName = values.getAsString(StructuredName.FAMILY_NAME);
83314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                } else {
83414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
83514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    // TODO compiled statement
83614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    familyName = DatabaseUtils.stringForQuery(db,
83714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            "SELECT " + StructuredName.FAMILY_NAME +
83814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            " FROM " + Tables.DATA +
83914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                            " WHERE " + Data._ID + "=" + dataId, null);
84014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                }
84114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
84214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                mOpenHelper.deleteNameLookup(dataId);
84314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                mOpenHelper.insertNameLookupForStructuredName(rawContactId, dataId, givenName,
84414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                        familyName);
84514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            }
84625abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
84714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
84814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
84914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
85014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
85114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
85214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
85314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
85414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
85514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
85614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.deleteNameLookup(dataId);
85725abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
85814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
8593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
8623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Parses the supplied display name, but only if the incoming values do not already contain
8633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * structured name parts.  Also, if the display name is not provided, generate one by
8643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * concatenating first name and last name
8653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         *
8663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * TODO see if the order of first and last names needs to be conditionally reversed for
8673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * some locales, e.g. China.
8683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
8693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private void fixStructuredNameComponents(ContentValues values) {
8703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String fullName = values.getAsString(StructuredName.DISPLAY_NAME);
8713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (!TextUtils.isEmpty(fullName)
8723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.PREFIX))
8733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.GIVEN_NAME))
8743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.MIDDLE_NAME))
8753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.FAMILY_NAME))
8763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.SUFFIX))) {
8773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                NameSplitter.Name name = new NameSplitter.Name();
8783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                mNameSplitter.split(name, fullName);
8793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.PREFIX, name.getPrefix());
8813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.GIVEN_NAME, name.getGivenNames());
8823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.MIDDLE_NAME, name.getMiddleName());
8833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.FAMILY_NAME, name.getFamilyName());
8843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.SUFFIX, name.getSuffix());
8853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (TextUtils.isEmpty(fullName)) {
8883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                String givenName = values.getAsString(StructuredName.GIVEN_NAME);
8893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                String familyName = values.getAsString(StructuredName.FAMILY_NAME);
8903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                if (TextUtils.isEmpty(givenName)) {
8913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = familyName;
8923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                } else if (TextUtils.isEmpty(familyName)) {
8933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = givenName;
8943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                } else {
8953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = givenName + " " + familyName;
8963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
8973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                if (!TextUtils.isEmpty(fullName)) {
8993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    values.put(StructuredName.DISPLAY_NAME, fullName);
9003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
9013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
9043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CommonDataRowHandler extends DataRowHandler {
9063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mTypeColumn;
9083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mLabelColumn;
9093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CommonDataRowHandler(String mimetype, String typeColumn, String labelColumn) {
9113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
9123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mTypeColumn = typeColumn;
9133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mLabelColumn = labelColumn;
9143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
9175ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
9183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            int type;
9193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String label;
9203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (values.containsKey(mTypeColumn)) {
9213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                type = values.getAsInteger(mTypeColumn);
9223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } else {
9233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                type = BaseTypes.TYPE_CUSTOM;
9243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (values.containsKey(mLabelColumn)) {
9263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                label = values.getAsString(mLabelColumn);
9273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } else {
9283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                label = null;
9293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (type != BaseTypes.TYPE_CUSTOM && label != null) {
9327a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException(mLabelColumn + " value can only be specified with "
9333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        + mTypeColumn + "=" + BaseTypes.TYPE_CUSTOM + "(custom)");
9343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (type == BaseTypes.TYPE_CUSTOM && label == null) {
9377a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException(mLabelColumn + " value must be specified when "
9383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        + mTypeColumn + "=" + BaseTypes.TYPE_CUSTOM + "(custom)");
9393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9415ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return super.insert(db, rawContactId, values);
9423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
9443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class OrganizationDataRowHandler extends CommonDataRowHandler {
9463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public OrganizationDataRowHandler() {
9483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Organization.CONTENT_ITEM_TYPE, Organization.TYPE, Organization.LABEL);
9493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
9525ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
9535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long id = super.insert(db, rawContactId, values);
95425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
9553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return id;
9563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
95914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
96014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                boolean markRawContactAsDirty) {
96114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
96214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
96314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super.update(db, values, c, markRawContactAsDirty);
96414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
96525abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
96614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
96714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
96814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
96914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
97014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
97114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
97214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
97325abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
97414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
97514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
97614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
97714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
9783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
9793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
9803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_WORK: return 0;
9813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_CUSTOM: return 1;
9823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_OTHER: return 2;
9833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
9843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
986a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
987a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
988a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
989a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return false;
990a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
9913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
9923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
993e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    public class EmailDataRowHandler extends CommonDataRowHandler {
994e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
995e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public EmailDataRowHandler() {
996e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            super(Email.CONTENT_ITEM_TYPE, Email.TYPE, Email.LABEL);
997e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
998e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
999e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
10005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
100114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String address = values.getAsString(Email.DATA);
100214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
100314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
100414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
100525abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
100614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.insertNameLookupForEmail(rawContactId, dataId, address);
100714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
100814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
100914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
101014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
101114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
101214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                boolean markRawContactAsDirty) {
101314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
101414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
101514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String address = values.getAsString(Email.DATA);
101614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
101714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super.update(db, values, c, markRawContactAsDirty);
101814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
101914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.deleteNameLookup(dataId);
102014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.insertNameLookupForEmail(rawContactId, dataId, address);
102125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
102214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
102314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
102414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
102514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
102614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
102714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
102814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
102914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
103014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
103114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.deleteNameLookup(dataId);
103225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
103314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
1034e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1035e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1036e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
1037e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
1038e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            switch (type) {
1039e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_HOME: return 0;
1040e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_WORK: return 1;
1041e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_CUSTOM: return 2;
1042e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_OTHER: return 3;
1043e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                default: return 1000;
1044e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
1045e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1046e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    }
1047e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
104814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    public class NicknameDataRowHandler extends CommonDataRowHandler {
104914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
105014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public NicknameDataRowHandler() {
105114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super(Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE, Nickname.LABEL);
105214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
105314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
105414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
105514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
105614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String nickname = values.getAsString(Nickname.NAME);
105714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
105814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = super.insert(db, rawContactId, values);
105914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
106025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
106114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.insertNameLookupForNickname(rawContactId, dataId, nickname);
106214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
106314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
106414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
106514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
106614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
106714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                boolean markRawContactAsDirty) {
106814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
106914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
107014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String nickname = values.getAsString(Nickname.NAME);
107114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
107214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super.update(db, values, c, markRawContactAsDirty);
107314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
107414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.deleteNameLookup(dataId);
107514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.insertNameLookupForNickname(rawContactId, dataId, nickname);
107625abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
107714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
107814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
107914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
108014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
108114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
108214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
108314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
108414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
108514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
108614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mOpenHelper.deleteNameLookup(dataId);
108725abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(db, rawContactId);
108814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
108914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
109014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    }
109114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
10923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class PhoneDataRowHandler extends CommonDataRowHandler {
10933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public PhoneDataRowHandler() {
10953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Phone.CONTENT_ITEM_TYPE, Phone.TYPE, Phone.LABEL);
10963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
10973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
10995ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
11000b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            long dataId;
11010b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            if (values.containsKey(Phone.NUMBER)) {
11020b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String number = values.getAsString(Phone.NUMBER);
11030b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String normalizedNumber = computeNormalizedNumber(number, values);
1104653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
11050b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                dataId = super.insert(db, rawContactId, values);
1106653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
11070b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
1108285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateHasPhoneNumber(db, rawContactId);
110925abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                fixRawContactDisplayName(db, rawContactId);
11100b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            } else {
11110b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                dataId = super.insert(db, rawContactId, values);
11120b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            }
1113653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return dataId;
1114653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1115653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1116653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1117653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1118653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                boolean markRawContactAsDirty) {
111914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
112014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
11210b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            if (values.containsKey(Phone.NUMBER)) {
11220b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String number = values.getAsString(Phone.NUMBER);
11230b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String normalizedNumber = computeNormalizedNumber(number, values);
1124653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
11250b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                super.update(db, values, c, markRawContactAsDirty);
1126653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
11270b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
1128285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateHasPhoneNumber(db, rawContactId);
112925abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                fixRawContactDisplayName(db, rawContactId);
11300b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            } else {
11310b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                super.update(db, values, c, markRawContactAsDirty);
11320b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            }
113314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
113414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
113514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
113614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
113714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
113814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
113914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
114014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            int count = super.delete(db, c);
114114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
114214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            updatePhoneLookup(db, rawContactId, dataId, null, null);
1143285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            mContactAggregator.updateHasPhoneNumber(db, rawContactId);
114425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            fixRawContactDisplayName(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);
1249285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            if (!isNewRawContact(rawContactId)) {
1250285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updatePhotoId(db, rawContactId);
1251285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
1252a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return dataId;
1253a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1254a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1255a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1256a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor c,
1257a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                boolean markRawContactAsDirty) {
1258a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1259a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            super.update(db, values, c, markRawContactAsDirty);
1260a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            mContactAggregator.updatePhotoId(db, rawContactId);
1261a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1262a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1263a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1264a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
1265a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
1266a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            int count = super.delete(db, c);
1267a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            mContactAggregator.updatePhotoId(db, rawContactId);
1268a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return count;
1269a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1270a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1271a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1272a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public boolean isAggregationRequired() {
1273a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return false;
1274a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1275a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov    }
1276a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1277a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
12783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private HashMap<String, DataRowHandler> mDataRowHandlers;
127953056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov    private final ContactAggregationScheduler mAggregationScheduler;
12804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    private OpenHelper mOpenHelper;
128131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
1282a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    private ContactAggregator mContactAggregator;
12834097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov    private NameSplitter mNameSplitter;
1284f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private LegacyApiSupport mLegacyApiSupport;
1285a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    private GlobalSearchSupport mGlobalSearchSupport;
1286a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
128720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private ContentValues mValues = new ContentValues();
128820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1289ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov    private volatile CountDownLatch mAccessLatch;
129073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private boolean mImportMode;
129173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1292de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    private boolean mScheduleAggregation;
1293285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    private ArrayList<Long> mInsertedRawContacts = new ArrayList<Long>();
1294de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov
1295a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    public ContactsProvider2() {
129653056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        this(new ContactAggregationScheduler());
1297a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1298a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1299a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
1300a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Constructor for testing.
1301a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
130253056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov    /* package */ ContactsProvider2(ContactAggregationScheduler scheduler) {
130353056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        mAggregationScheduler = scheduler;
1304a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
13054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
13064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
13074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public boolean onCreate() {
1308de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        super.onCreate();
130935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1310de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final Context context = getContext();
1311de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mOpenHelper = (OpenHelper)getOpenHelper();
1312a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mGlobalSearchSupport = new GlobalSearchSupport(this);
1313a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mLegacyApiSupport = new LegacyApiSupport(context, mOpenHelper, this, mGlobalSearchSupport);
1314cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov        mContactAggregator = new ContactAggregator(this, mOpenHelper, mAggregationScheduler);
1315a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1316d51a83ac4f8032b62d9a23b90a8f43d6b7eb2dbbDmitri Plotnikov        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1317653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1318c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement = db.compileStatement(
1319653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "UPDATE " + Tables.DATA +
1320653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " SET " + Data.IS_PRIMARY + "=(_id=?)" +
1321653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " WHERE " + DataColumns.MIMETYPE_ID + "=?" +
1322653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "   AND " + Data.RAW_CONTACT_ID + "=?");
1323653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1324c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement = db.compileStatement(
1325653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "UPDATE " + Tables.DATA +
1326653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " SET " + Data.IS_SUPER_PRIMARY + "=(" + Data._ID + "=?)" +
1327653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                " WHERE " + DataColumns.MIMETYPE_ID + "=?" +
1328653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                "   AND " + Data.RAW_CONTACT_ID + " IN (" +
1329653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        "SELECT " + RawContacts._ID +
1330653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        " FROM " + Tables.RAW_CONTACTS +
1331653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        " WHERE " + RawContacts.CONTACT_ID + " =(" +
1332653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                "SELECT " + RawContacts.CONTACT_ID +
1333653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                " FROM " + Tables.RAW_CONTACTS +
1334653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                " WHERE " + RawContacts._ID + "=?))");
1335653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
13365ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mLastTimeContactedUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
13376cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                + RawContacts.TIMES_CONTACTED + "=" + RawContacts.TIMES_CONTACTED + "+1,"
1338d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + RawContacts.LAST_TIME_CONTACTED + "=? WHERE " + RawContacts.CONTACT_ID + "=?");
1339a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
134025abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        mRawContactDisplayNameUpdate = db.compileStatement(
134125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                "UPDATE " + Tables.RAW_CONTACTS +
134225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                " SET " + RawContactsColumns.DISPLAY_NAME + "=?,"
134325abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                        + RawContactsColumns.DISPLAY_NAME_SOURCE + "=?" +
134425abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov                " WHERE " + RawContacts._ID + "=?");
13453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
134673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
134773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                + RawContacts.DIRTY + "=1 WHERE " + RawContacts._ID + "=?");
134873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1349e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        mAggregatedPresenceReplace = db.compileStatement(
1350e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                "INSERT OR REPLACE INTO " + Tables.AGGREGATED_PRESENCE + "("
1351e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + AggregatedPresenceColumns.CONTACT_ID + ", "
1352e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + Presence.PRESENCE_STATUS
1353e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                + ") VALUES (?, (SELECT MAX(" + Presence.PRESENCE_STATUS + ")"
1354e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + " FROM " + Tables.PRESENCE + "," + Tables.RAW_CONTACTS
1355a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                        + " WHERE " + PresenceColumns.RAW_CONTACT_ID + "="
1356e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                                + RawContactsColumns.CONCRETE_ID
1357e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + "   AND " + RawContacts.CONTACT_ID + "=?))");
1358e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
1359e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        mAggregatedPresenceStatusUpdate = db.compileStatement(
1360e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                "UPDATE " + Tables.AGGREGATED_PRESENCE
1361e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                + " SET " + Presence.PRESENCE_CUSTOM_STATUS + "=? "
1362e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                + " WHERE " + AggregatedPresenceColumns.CONTACT_ID + "=?");
1363e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
136428f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar        mNameSplitter = new NameSplitter(
136528f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_prefixes),
136628f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_last_name_prefixes),
136728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_suffixes),
136828f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_conjunctions));
13694097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
13703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers = new HashMap<String, DataRowHandler>();
13713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1372e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, new EmailDataRowHandler());
13733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE,
13743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new CommonDataRowHandler(Im.CONTENT_ITEM_TYPE, Im.TYPE, Im.LABEL));
137567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler(
137667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, StructuredPostal.LABEL));
13773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, new OrganizationDataRowHandler());
13783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, new PhoneDataRowHandler());
137914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new NicknameDataRowHandler());
13803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE,
13813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new StructuredNameRowHandler(mNameSplitter));
1382a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        mDataRowHandlers.put(GroupMembership.CONTENT_ITEM_TYPE, new GroupMembershipRowHandler());
1383a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        mDataRowHandlers.put(Photo.CONTENT_ITEM_TYPE, new PhotoDataRowHandler());
13843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
13853d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        if (isLegacyContactImportNeeded()) {
1386568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            importLegacyContactsAsync();
13873d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
1388568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
13891f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        return (db != null);
13904f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
13914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
139231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    /* Visible for testing */
1393de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    @Override
139431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    protected OpenHelper getOpenHelper(final Context context) {
139531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov        return OpenHelper.getInstance(context);
139631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    }
139731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
1398285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    /* package */ ContactAggregationScheduler getContactAggregationScheduler() {
1399285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        return mAggregationScheduler;
1400285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
1401285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
1402013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    /* package */ NameSplitter getNameSplitter() {
1403013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov        return mNameSplitter;
1404013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    }
1405013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov
14063d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    protected boolean isLegacyContactImportNeeded() {
14073d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
14083d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        return prefs.getInt(PREF_CONTACTS_IMPORTED, 0) < PREF_CONTACTS_IMPORT_VERSION;
14093d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
14103d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1411568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    protected LegacyContactImporter getLegacyContactImporter() {
1412568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return new LegacyContactImporter(getContext(), this);
1413568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1414568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1415568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /**
1416568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * Imports legacy contacts in a separate thread.  As long as the import process is running
1417568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * all other access to the contacts is blocked.
1418568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     */
1419568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    private void importLegacyContactsAsync() {
1420ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        mAccessLatch = new CountDownLatch(1);
1421568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1422568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        Thread importThread = new Thread("LegacyContactImport") {
1423568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            @Override
1424568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            public void run() {
1425568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                if (importLegacyContacts()) {
1426568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1427568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                    /*
1428568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     * When the import process is done, we can unlock the provider and
1429568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     * start aggregating the imported contacts asynchronously.
1430568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                     */
1431ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch.countDown();
1432ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch = null;
1433568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                    scheduleContactAggregation();
1434568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                }
1435568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            }
1436568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        };
1437568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1438568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        importThread.start();
1439568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1440568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
14413d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private boolean importLegacyContacts() {
1442568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        LegacyContactImporter importer = getLegacyContactImporter();
1443568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        if (importLegacyContacts(importer)) {
14443d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
14453d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            Editor editor = prefs.edit();
14463d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            editor.putInt(PREF_CONTACTS_IMPORTED, PREF_CONTACTS_IMPORT_VERSION);
14473d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            editor.commit();
14483d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return true;
14493d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        } else {
14503d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return false;
14513d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
14523d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
14533d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
14543d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /* Visible for testing */
1455568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /* package */ boolean importLegacyContacts(LegacyContactImporter importer) {
14563d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        mContactAggregator.setEnabled(false);
145773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mImportMode = true;
14583d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        try {
14593d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            importer.importContacts();
14603d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            mContactAggregator.setEnabled(true);
14613d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return true;
14623d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        } catch (Throwable e) {
14633d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov           Log.e(TAG, "Legacy contact import failed", e);
14643d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov           return false;
146573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        } finally {
146673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            mImportMode = false;
14673d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
14683d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
14693d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1470a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    @Override
1471a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    protected void finalize() throws Throwable {
1472a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        if (mContactAggregator != null) {
1473a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov            mContactAggregator.quit();
1474a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        }
1475a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1476a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        super.finalize();
1477a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1478a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1479a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
1480a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Wipes all data from the contacts database.
1481a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
1482a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /* package */ void wipeData() {
1483a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        mOpenHelper.wipeData();
1484a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1485a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1486568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /**
1487568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * While importing and aggregating contacts, this content provider will
1488568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * block all attempts to change contacts data. In particular, it will hold
1489568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * up all contact syncs. As soon as the import process is complete, all
1490568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * processes waiting to write to the provider are unblocked and can proceed
1491568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * to compete for the database transaction monitor.
1492568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     */
1493568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    private void waitForAccess() {
1494ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        CountDownLatch latch = mAccessLatch;
1495ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        if (latch != null) {
1496ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov            while (true) {
1497ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                try {
1498ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    latch.await();
1499ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch = null;
1500ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    return;
1501ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                } catch (InterruptedException e) {
1502ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                }
1503ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov            }
1504568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        }
1505568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1506568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1507568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1508568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public Uri insert(Uri uri, ContentValues values) {
1509568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1510568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.insert(uri, values);
1511568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1512568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1513568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1514568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
1515568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1516568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.update(uri, values, selection, selectionArgs);
1517568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1518568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1519568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1520568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public int delete(Uri uri, String selection, String[] selectionArgs) {
1521568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1522568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.delete(uri, selection, selectionArgs);
1523568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1524568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1525568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
1526568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
1527568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            throws OperationApplicationException {
1528568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
1529568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.applyBatch(operations);
1530568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1531568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
15324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
1533285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    protected void onBeginTransaction() {
1534285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        super.onBeginTransaction();
1535285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        mInsertedRawContacts.clear();
1536285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
1537285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
1538285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    @Override
1539285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    protected void beforeTransactionCommit() {
1540285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        super.beforeTransactionCommit();
1541285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        int count = mInsertedRawContacts.size();
1542285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        for (int i = 0; i < count; i++) {
1543285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            mContactAggregator.insertContact(mDb, mInsertedRawContacts.get(i));
1544285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        }
1545285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
1546285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
1547285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    @Override
1548285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    protected void onEndTransaction() {
1549de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (mScheduleAggregation) {
1550de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            mScheduleAggregation = false;
1551568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            scheduleContactAggregation();
1552de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
1553285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        super.onEndTransaction();
15544f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
15554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1556cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    @Override
1557cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    protected void notifyChange() {
1558cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov        getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null);
1559cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    }
1560568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1561568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    protected void scheduleContactAggregation() {
1562568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        mContactAggregator.schedule();
1563568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
1564568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
1565285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    private boolean isNewRawContact(long rawContactId) {
1566285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        return mInsertedRawContacts.contains(rawContactId);
1567285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
1568285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
15693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private DataRowHandler getDataRowHandler(final String mimeType) {
15703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        DataRowHandler handler = mDataRowHandlers.get(mimeType);
15713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (handler == null) {
15723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            handler = new CustomDataRowHandler(mimeType);
15733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mDataRowHandlers.put(mimeType, handler);
15743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
15753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        return handler;
15763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
15773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
15784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
1579de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected Uri insertInTransaction(Uri uri, ContentValues values) {
1580a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
1581a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
158235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1583a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        switch (match) {
158435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
1585de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                id = mOpenHelper.getSyncState().insert(mDb, values);
158635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                break;
158735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1588d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
1589d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                insertContact(values);
15906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
15916bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
15926bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
15935ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
1594f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                final Account account = readAccountFromQueryParams(uri);
1595d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                id = insertRawContact(values, account);
1596a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1597a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1598a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
15995ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
16005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1));
160173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                id = insertData(values, shouldMarkRawContactAsDirty(uri));
1602a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1603a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1604a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1605a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case DATA: {
160673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                id = insertData(values, shouldMarkRawContactAsDirty(uri));
1607a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1608a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1609a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1610ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
1611ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                final Account account = readAccountFromQueryParams(uri);
161273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                id = insertGroup(values, account, shouldMarkGroupAsDirty(uri));
1613ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
1614ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1615ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1616eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
1617e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                id = insertSettings(values);
1618eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
1619eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
1620eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
16211f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            case PRESENCE: {
16221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                id = insertPresence(values);
16231f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                break;
16241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
16251f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
1626a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            default:
1627f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.insert(uri, values);
1628a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
1629a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
16307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        if (id < 0) {
16317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return null;
16327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
16337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
1634de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return ContentUris.withAppendedId(uri, id);
1635a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
1636a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1637a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
1638035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * If account is non-null then store it in the values. If the account is already
1639035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * specified in the values then it must be consistent with the account, if it is non-null.
1640035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @param values the ContentValues to read from and update
1641035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @param account the explicitly provided Account
1642035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @return false if the accounts are inconsistent
16437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
1644035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana    private boolean resolveAccount(ContentValues values, Account account) {
1645035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        // If either is specified then both must be specified.
16466cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
16476cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
1648035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        if (!TextUtils.isEmpty(accountName) || !TextUtils.isEmpty(accountType)) {
1649035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            final Account valuesAccount = new Account(accountName, accountType);
1650035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            if (account != null && !valuesAccount.equals(account)) {
1651035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                return false;
1652035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            }
1653035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            account = valuesAccount;
1654035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
1655035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        if (account != null) {
1656df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana            values.put(RawContacts.ACCOUNT_NAME, account.name);
1657df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana            values.put(RawContacts.ACCOUNT_TYPE, account.type);
1658035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
1659035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        return true;
16607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
16617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
16627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
1663d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov     * Inserts an item in the contacts table
16646bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     *
16656bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @param values the values for the new row
16666bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @return the row ID of the newly created row
16676bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     */
1668d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertContact(ContentValues values) {
1669de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        throw new UnsupportedOperationException("Aggregate contacts are created automatically");
16706bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    }
16716bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
16726bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    /**
1673a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the contacts table
1674a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
1675a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
1676f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana     * @param account the account this contact should be associated with. may be null.
1677a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
1678a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
1679d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertRawContact(ContentValues values, Account account) {
1680a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        ContentValues overriddenValues = new ContentValues(values);
1681d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        overriddenValues.putNull(RawContacts.CONTACT_ID);
1682f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        if (!resolveAccount(overriddenValues, account)) {
16837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return -1;
16847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
16857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
16863d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        if (values.containsKey(RawContacts.DELETED)
16873d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov                && values.getAsInteger(RawContacts.DELETED) != 0) {
16883d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            overriddenValues.put(RawContacts.AGGREGATION_MODE,
16893d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov                    RawContacts.AGGREGATION_MODE_DISABLED);
16903d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
16913d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1692023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        long rawContactId =
1693023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov                mDb.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, overriddenValues);
1694023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        mContactAggregator.markNewForAggregation(rawContactId);
1695285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
1696285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        // Trigger creation of a Contact based on this RawContact at the end of transaction
1697285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        mInsertedRawContacts.add(rawContactId);
1698023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        return rawContactId;
1699a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
1700a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1701a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
1702a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the data table
1703a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
1704a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
1705a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
1706a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
170773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private long insertData(ContentValues values, boolean markRawContactAsDirty) {
1708a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
1709de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.clear();
1710de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.putAll(values);
171167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
1712de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID);
171320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1714de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace package with internal mapping
1715de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String packageName = mValues.getAsString(Data.RES_PACKAGE);
1716de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (packageName != null) {
1717de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
1718de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
1719de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.RES_PACKAGE);
1720508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
1721de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace mimetype with internal mapping
1722de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String mimeType = mValues.getAsString(Data.MIMETYPE);
1723de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (TextUtils.isEmpty(mimeType)) {
1724de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            throw new IllegalArgumentException(Data.MIMETYPE + " is required");
1725de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
17264097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
1727de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.put(DataColumns.MIMETYPE_ID, mOpenHelper.getMimeTypeId(mimeType));
1728de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
1729a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1730a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        DataRowHandler rowHandler = getDataRowHandler(mimeType);
1731a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        id = rowHandler.insert(mDb, rawContactId, mValues);
1732de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (markRawContactAsDirty) {
1733de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            setRawContactDirty(rawContactId);
1734a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
1735a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1736a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        if (rowHandler.isAggregationRequired()) {
1737a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            triggerAggregation(rawContactId);
1738a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1739a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        return id;
17404f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
17414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
17428e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov    private void triggerAggregation(long rawContactId) {
17438e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        if (!mContactAggregator.isEnabled()) {
17448e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            return;
17458e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        }
17468e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
17478e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        int aggregationMode = mOpenHelper.getAggregationMode(rawContactId);
1748f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        switch (aggregationMode) {
17498e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DISABLED:
17508e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                break;
17518e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
17528e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DEFAULT: {
1753421782cb554e5050cf62a86b98df6520038dcd15Dmitri Plotnikov                mContactAggregator.markForAggregation(rawContactId);
1754de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                mScheduleAggregation = true;
1755f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
17568e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
17578e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
17588e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_SUSPENDED: {
17598e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                long contactId = mOpenHelper.getContactId(rawContactId);
1760f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
17618e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                if (contactId != 0) {
17628e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                    mContactAggregator.updateAggregateData(contactId);
17638e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                }
1764f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
17658e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
1766f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
17678e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_IMMEDITATE: {
17688e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                long contactId = mOpenHelper.getContactId(rawContactId);
1769421782cb554e5050cf62a86b98df6520038dcd15Dmitri Plotnikov                mContactAggregator.markForAggregation(rawContactId);
17708e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                mContactAggregator.aggregateContact(mDb, rawContactId, contactId);
1771f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
17728e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
1773f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        }
1774f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
1775f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
1776a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
17775ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * Returns the group id of the group with sourceId and the same account as rawContactId.
17789261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * If the group doesn't already exist then it is first created,
17799261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param db SQLiteDatabase to use for this operation
17805ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * @param rawContactId the contact this group is associated with
17819261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param sourceId the sourceIf of the group to query or create
17829261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @return the group id of the existing or created group
17839261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalArgumentException if the contact is not associated with an account
17849261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalStateException if a group needs to be created but the creation failed
17859261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     */
17865ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private long getOrMakeGroup(SQLiteDatabase db, long rawContactId, String sourceId) {
17879261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        Account account = null;
17886cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Cursor c = db.query(ContactsQuery.TABLE, ContactsQuery.PROJECTION, RawContacts._ID + "="
17895ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                + rawContactId, null, null, null, null);
17909261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
17919261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            if (c.moveToNext()) {
179267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                final String accountName = c.getString(ContactsQuery.ACCOUNT_NAME);
179367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                final String accountType = c.getString(ContactsQuery.ACCOUNT_TYPE);
17949261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
17959261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    account = new Account(accountName, accountType);
17969261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
17979261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
17989261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
17999261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
18009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
18019261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        if (account == null) {
18029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            throw new IllegalArgumentException("if the groupmembership only "
18039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "has a sourceid the the contact must be associate with "
18049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "an account");
18059261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
18069261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
18079261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // look up the group that contains this sourceId and has the same account name and type
18085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        // as the contact refered to by rawContactId
18096cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        c = db.query(Tables.GROUPS, new String[]{RawContacts._ID},
18109261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Clauses.GROUP_HAS_ACCOUNT_AND_SOURCE_ID,
1811df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                new String[]{sourceId, account.name, account.type}, null, null, null);
18129261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
18139261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            if (c.moveToNext()) {
18149261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                return c.getLong(0);
18159261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            } else {
18169261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                ContentValues groupValues = new ContentValues();
1817df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                groupValues.put(Groups.ACCOUNT_NAME, account.name);
1818df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                groupValues.put(Groups.ACCOUNT_TYPE, account.type);
18199261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                groupValues.put(Groups.SOURCE_ID, sourceId);
18209261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                long groupId = db.insert(Tables.GROUPS, Groups.ACCOUNT_NAME, groupValues);
18219261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (groupId < 0) {
18229261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    throw new IllegalStateException("unable to create a new group with "
18239261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            + "this sourceid: " + groupValues);
18249261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
18259261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                return groupId;
18269261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
18279261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
18289261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
18299261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
18309261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    }
18319261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
18329261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /**
183320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     * Delete data row by row so that fixing of primaries etc work correctly.
183420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     */
183573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private int deleteData(String selection, String[] selectionArgs,
183673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            boolean markRawContactAsDirty) {
183720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int count = 0;
183820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1839de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
1840de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
184114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, selection, selectionArgs, null);
1842de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        try {
1843de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            while(c.moveToNext()) {
184414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
184514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
1846a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                DataRowHandler rowHandler = getDataRowHandler(mimeType);
1847a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                count += rowHandler.delete(mDb, c);
184888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                if (markRawContactAsDirty) {
184988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                    setRawContactDirty(rawContactId);
1850a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                    if (rowHandler.isAggregationRequired()) {
1851a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                        triggerAggregation(rawContactId);
1852a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                    }
185388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                }
185420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
185520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
1856de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            c.close();
185720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
185820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
185920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        return count;
186020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
186120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
186288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov    /**
186388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     * Delete a data row provided that it is one of the allowed mime types.
186488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     */
186520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    public int deleteData(long dataId, String[] allowedMimeTypes) {
1866f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
186788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
186888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
186914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, Data._ID + "=" + dataId, null,
187014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                null);
1871f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
187220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        try {
187320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!c.moveToFirst()) {
187420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                return 0;
187520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
187620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
187714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
187820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            boolean valid = false;
187920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            for (int i = 0; i < allowedMimeTypes.length; i++) {
188020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                if (TextUtils.equals(mimeType, allowedMimeTypes[i])) {
188120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    valid = true;
188220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    break;
188320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                }
188420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
188520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
188620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!valid) {
18877a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException("Data type mismatch: expected "
188820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                        + Lists.newArrayList(allowedMimeTypes));
188920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
189020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1891a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            DataRowHandler rowHandler = getDataRowHandler(mimeType);
1892a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            int count = rowHandler.delete(mDb, c);
18938e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
1894a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            if (rowHandler.isAggregationRequired()) {
1895a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                triggerAggregation(rawContactId);
1896a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            }
18978e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            return count;
189820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
189920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            c.close();
190020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
190120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
190220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
190320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    /**
1904ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Inserts an item in the groups table
1905ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
190673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private long insertGroup(ContentValues values, Account account, boolean markAsDirty) {
1907ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        ContentValues overriddenValues = new ContentValues(values);
1908ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        if (!resolveAccount(overriddenValues, account)) {
1909ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            return -1;
1910ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        }
1911ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1912ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Replace package with internal mapping
191367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        final String packageName = overriddenValues.getAsString(Groups.RES_PACKAGE);
191467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        if (packageName != null) {
191567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            overriddenValues.put(GroupsColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
191667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        }
191767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        overriddenValues.remove(Groups.RES_PACKAGE);
1918ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
191973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (markAsDirty) {
192073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            overriddenValues.put(Groups.DIRTY, 1);
192173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
192273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1923ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        long result = mDb.insert(Tables.GROUPS, Groups.TITLE, overriddenValues);
1924ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey
1925ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        if (overriddenValues.containsKey(Groups.GROUP_VISIBLE)) {
1926ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey            mOpenHelper.updateAllVisible();
1927ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        }
1928ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey
1929ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        return result;
1930ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
1931ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1932e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    private long insertSettings(ContentValues values) {
1933e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final long id = mDb.insert(Tables.SETTINGS, null, values);
1934e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        if (values.containsKey(Settings.UNGROUPED_VISIBLE)) {
1935e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey            mOpenHelper.updateAllVisible();
1936e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
1937e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return id;
1938e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
1939e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
1940ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
19411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     * Inserts a presence update.
19421f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     */
194370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    public long insertPresence(ContentValues values) {
19441f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        final String handle = values.getAsString(Presence.IM_HANDLE);
19454dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        if (TextUtils.isEmpty(handle) || !values.containsKey(Presence.PROTOCOL)) {
19464dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required");
19474dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        }
19484dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov
19494dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        final long protocol = values.getAsLong(Presence.PROTOCOL);
19504dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        String customProtocol = null;
19514dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov
19524dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        if (protocol == Im.PROTOCOL_CUSTOM) {
19534dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            customProtocol = values.getAsString(Presence.CUSTOM_PROTOCOL);
19544dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            if (TextUtils.isEmpty(customProtocol)) {
19554dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                throw new IllegalArgumentException(
19564dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                        "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM");
19574dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            }
19581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
19591f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
19601f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        // TODO: generalize to allow other providers to match against email
19614dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol;
19621f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
196370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        StringBuilder selection = new StringBuilder();
19641f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String[] selectionArgs;
19651f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        if (matchEmail) {
19664dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            selection.append(
19674dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    "((" + MimetypesColumns.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'"
19684dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + " AND " + Im.PROTOCOL + "=?"
19694dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + " AND " + Im.DATA + "=?");
19704dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            if (customProtocol != null) {
19714dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                selection.append(" AND " + Im.CUSTOM_PROTOCOL + "=");
19724dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(selection, customProtocol);
19734dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            }
19744dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            selection.append(") OR ("
19754dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + MimetypesColumns.MIMETYPE + "='" + Email.CONTENT_ITEM_TYPE + "'"
19764dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + " AND " + Email.DATA + "=?"
19774dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + "))");
19784dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            selectionArgs = new String[] { String.valueOf(protocol), handle, handle };
19791f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } else {
19804dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            selection.append(
19814dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    MimetypesColumns.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'"
19824dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + " AND " + Im.PROTOCOL + "=?"
19834dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                    + " AND " + Im.DATA + "=?");
19844dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            if (customProtocol != null) {
19854dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                selection.append(" AND " + Im.CUSTOM_PROTOCOL + "=");
19864dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(selection, customProtocol);
19874dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            }
19884dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov
19894dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            selectionArgs = new String[] { String.valueOf(protocol), handle };
19901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
19911f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
199270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (values.containsKey(Presence.DATA_ID)) {
199370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            selection.append(" AND " + DataColumns.CONCRETE_ID + "=")
199470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                    .append(values.getAsLong(Presence.DATA_ID));
199570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
199670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
199700ec508630251d6c6e3746469c9428f5a8cd5996Jeff Sharkey        selection.append(" AND ").append(getContactsRestrictions());
199870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
19991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        long dataId = -1;
20005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        long rawContactId = -1;
2001e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        long contactId = -1;
200270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
20031f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        Cursor cursor = null;
20041f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        try {
2005de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION,
200670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                    selection.toString(), selectionArgs, null, null, null);
20071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            if (cursor.moveToFirst()) {
200867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                dataId = cursor.getLong(DataContactsQuery.DATA_ID);
20095ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID);
2010e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                contactId = cursor.getLong(DataContactsQuery.CONTACT_ID);
20111f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            } else {
20121f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                // No contact found, return a null URI
20131f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                return -1;
20141f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
20151f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } finally {
201631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            if (cursor != null) {
201731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                cursor.close();
201831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
20191f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
20201f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
20211f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        values.put(Presence.DATA_ID, dataId);
20224dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        values.put(PresenceColumns.RAW_CONTACT_ID, rawContactId);
20231f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
20241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        // Insert the presence update
2025de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        long presenceId = mDb.replace(Tables.PRESENCE, null, values);
2026e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
2027e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        if (contactId != -1) {
2028e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            if (values.containsKey(Presence.PRESENCE_STATUS)) {
2029e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceReplace.bindLong(1, contactId);
2030e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceReplace.bindLong(2, contactId);
2031e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceReplace.execute();
2032e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            }
2033e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            String status = values.getAsString(Presence.PRESENCE_CUSTOM_STATUS);
2034e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            if (status != null) {
2035e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceStatusUpdate.bindString(1, status);
2036e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceStatusUpdate.bindLong(2, contactId);
2037e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                mAggregatedPresenceStatusUpdate.execute();
2038e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            }
2039e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        }
20401f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        return presenceId;
20411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    }
20421f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
20434f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
2044de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
2045508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        final int match = sUriMatcher.match(uri);
2046508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        switch (match) {
204735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
2048de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mOpenHelper.getSyncState().delete(mDb, selection, selectionArgs);
204935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2050d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
2051d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
20526bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
2053d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                // Remove references to the contact first
20546bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                ContentValues values = new ContentValues();
2055d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values.putNull(RawContacts.CONTACT_ID);
2056de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                mDb.update(Tables.RAW_CONTACTS, values,
2057d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        RawContacts.CONTACT_ID + "=" + contactId, null);
20586bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
2059de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.delete(Tables.CONTACTS, BaseColumns._ID + "=" + contactId, null);
20606bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
20616bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
20622971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            case RAW_CONTACTS: {
20632971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                final boolean permanently =
20642971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        readBooleanQueryParameter(uri, RawContacts.DELETE_PERMANENTLY, false);
20652971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                int numDeletes = 0;
20662971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                Cursor c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID},
2067e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs, null, null, null);
20682971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                try {
20692971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    while (c.moveToNext()) {
20702971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        final long rawContactId = c.getLong(0);
20712971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        numDeletes += deleteRawContact(rawContactId, permanently);
20722971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    }
20732971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                } finally {
20742971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    c.close();
20752971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                }
20762971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return numDeletes;
20772971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            }
20782971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana
20795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
20802971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                final boolean permanently =
20812971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        readBooleanQueryParameter(uri, RawContacts.DELETE_PERMANENTLY, false);
20822971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                final long rawContactId = ContentUris.parseId(uri);
20832971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return deleteRawContact(rawContactId, permanently);
2084508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
2085508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
208620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
2087944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                return deleteData(appendAccountToSelection(uri, selection), selectionArgs,
2088944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                        shouldMarkRawContactAsDirty(uri));
208920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
209020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2091508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            case DATA_ID: {
2092508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey                long dataId = ContentUris.parseId(uri);
2093f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov                return deleteData(Data._ID + "=" + dataId, null, shouldMarkRawContactAsDirty(uri));
2094ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2095ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2096ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
20972971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                boolean markAsDirty = shouldMarkGroupAsDirty(uri);
20982971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                final boolean deletePermanently =
20992971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        readBooleanQueryParameter(uri, Groups.DELETE_PERMANENTLY, false);
21002971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return deleteGroup(ContentUris.parseId(uri), markAsDirty, deletePermanently);
21012971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            }
21022971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana
21032971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            case GROUPS: {
21042971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                boolean markAsDirty = shouldMarkGroupAsDirty(uri);
21056f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov                final boolean permanently =
21062971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        readBooleanQueryParameter(uri, RawContacts.DELETE_PERMANENTLY, false);
21072971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                int numDeletes = 0;
21082971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups._ID},
2109e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs, null, null, null);
21102971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                try {
21112971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    while (c.moveToNext()) {
21122971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        numDeletes += deleteGroup(c.getLong(0), markAsDirty, permanently);
21132971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    }
21142971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                } finally {
21152971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    c.close();
21162971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                }
21172971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return numDeletes;
2118508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
2119508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
2120eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
2121e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                return deleteSettings(selection, selectionArgs);
2122eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
2123eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
21241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            case PRESENCE: {
2125eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                return mDb.delete(Tables.PRESENCE, selection, selectionArgs);
21261f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
21271f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2128508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            default:
21293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                return mLegacyApiSupport.delete(uri, selection, selectionArgs);
2130508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        }
21314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
21324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
21332971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana    private boolean readBooleanQueryParameter(Uri uri, String name, boolean defaultValue) {
21342971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana        final String flag = uri.getQueryParameter(name);
21352971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana        return flag == null
21362971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                ? defaultValue
21372971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                : (!"false".equals(flag.toLowerCase()) && !"0".equals(flag.toLowerCase()));
213894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
213994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
214073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private int deleteGroup(long groupId, boolean markAsDirty, boolean permanently) {
214194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        final long groupMembershipMimetypeId = mOpenHelper
214294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
2143de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mDb.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "="
214494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "="
214594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupId, null);
214694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
214794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        try {
214894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            if (permanently) {
2149de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null);
215094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            } else {
215194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.clear();
215294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.put(Groups.DELETED, 1);
215373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                if (markAsDirty) {
215473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                    mValues.put(Groups.DIRTY, 1);
215573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                }
2156de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, null);
215794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            }
215894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        } finally {
215994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            mOpenHelper.updateAllVisible();
216094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
216194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
216294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
2163e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    private int deleteSettings(String selection, String[] selectionArgs) {
2164e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final int count = mDb.delete(Tables.SETTINGS, selection, selectionArgs);
2165e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        if (count > 0) {
2166e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey            mOpenHelper.updateAllVisible();
2167e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
2168e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return count;
2169e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
2170e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
21715ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public int deleteRawContact(long rawContactId, boolean permanently) {
2172c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        // TODO delete aggregation exceptions
2173c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        mOpenHelper.removeContactIfSingleton(rawContactId);
217433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        if (permanently) {
217514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mDb.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null);
2176de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            return mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null);
217733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        } else {
217811944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov
217911944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov            // Clear out data used for aggregation - this deleted contact should not be aggregated
218011944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov            mDb.execSQL("DELETE FROM " + Tables.NAME_LOOKUP + " WHERE "
218111944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov                    + NameLookupColumns.RAW_CONTACT_ID + "=" + rawContactId);
218211944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov
218333b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov            mValues.clear();
218494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            mValues.put(RawContacts.DELETED, 1);
2185c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
2186c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            mValues.putNull(RawContacts.CONTACT_ID);
218773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            mValues.put(RawContacts.DIRTY, 1);
21885ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return updateRawContact(rawContactId, mValues, null, null);
218933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        }
219033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
219133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
2192f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana    private static Account readAccountFromQueryParams(Uri uri) {
21936cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String name = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
21946cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String type = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
2195f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(type)) {
2196f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana            return null;
2197f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        }
2198f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        return new Account(name, type);
2199f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana    }
2200f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana
22014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
2202de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int updateInTransaction(Uri uri, ContentValues values, String selection,
2203de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            String[] selectionArgs) {
220435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        int count = 0;
220500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
220600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        final int match = sUriMatcher.match(uri);
220700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        switch(match) {
220835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
2209de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mOpenHelper.getSyncState().update(mDb, values, selection, selectionArgs);
221035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2211d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            // TODO(emillar): We will want to disallow editing the contacts table at some point.
2212d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
2213944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                count = mDb.update(Tables.CONTACTS, values,
2214944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs);
221500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
221600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
221700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
2218d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
2219de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateContactData(ContentUris.parseId(uri), values);
2220c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                break;
2221c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar            }
2222c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
222320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
2224944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                count = updateData(uri, values, appendAccountToSelection(uri, selection),
2225944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                        selectionArgs, shouldMarkRawContactAsDirty(uri));
222620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                break;
222720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
2228c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
222920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA_ID: {
223073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                count = updateData(uri, values, selection, selectionArgs,
223173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        shouldMarkRawContactAsDirty(uri));
223200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
223300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
22347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
22355ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
223673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                // TODO: security checks
2237e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                count = mDb.update(Tables.RAW_CONTACTS, values,
2238e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs);
2239433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey
2240433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey                if (values.containsKey(RawContacts.STARRED)) {
2241433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey                    mContactAggregator.updateStarred(mDb, selection, selectionArgs);
2242433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey                }
22437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
22447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
22457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
22465ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
224733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
224833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                count = updateRawContact(rawContactId, values, selection, selectionArgs);
22497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
22507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
22517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
2252ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
2253e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                count = updateGroups(values, appendAccountToSelection(uri, selection),
2254e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        selectionArgs, shouldMarkGroupAsDirty(uri));
2255ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2256ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2257ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2258ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
2259ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
226073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                String selectionWithId = (Groups._ID + "=" + groupId + " ")
226173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        + (selection == null ? "" : " AND " + selection);
2262de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateGroups(values, selectionWithId, selectionArgs,
226373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        shouldMarkGroupAsDirty(uri));
2264ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2265ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2266ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2267127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
2268de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateAggregationException(mDb, values);
2269b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
2270b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
2271b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
2272eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
2273e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                count = updateSettings(values, selection, selectionArgs);
2274eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
2275eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
2276eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
22777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            default:
2278f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.update(uri, values, selection, selectionArgs);
227900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        }
228000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
228100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        return count;
22824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
22834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
2284de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    private int updateGroups(ContentValues values, String selectionWithId,
228573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            String[] selectionArgs, boolean markAsDirty) {
228673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
228773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        ContentValues updatedValues;
228873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (markAsDirty) {
228973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = mValues;
229073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.clear();
229173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.putAll(values);
229273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.put(Groups.DIRTY, 1);
229373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        } else {
229473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = values;
229573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
229673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
2297ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        int count = mDb.update(Tables.GROUPS, updatedValues, selectionWithId, selectionArgs);
229894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
229994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        // If changing visibility, then update contacts
2300ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) {
230194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            mOpenHelper.updateAllVisible();
230294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
230394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        return count;
230494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
230594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
2306e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    private int updateSettings(ContentValues values, String selection, String[] selectionArgs) {
2307e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final int count = mDb.update(Tables.SETTINGS, values, selection, selectionArgs);
2308e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        if (values.containsKey(Settings.UNGROUPED_VISIBLE)) {
2309e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey            mOpenHelper.updateAllVisible();
2310e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
2311e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return count;
2312e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
2313e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
23145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private int updateRawContact(long rawContactId, ContentValues values, String selection,
231533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov            String[] selectionArgs) {
231673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
231773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        // TODO: security checks
23185ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        String selectionWithId = (RawContacts._ID + " = " + rawContactId + " ")
231933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                + (selection == null ? "" : " AND " + selection);
23205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int count = mDb.update(Tables.RAW_CONTACTS, values, selectionWithId, selectionArgs);
23215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (count != 0) {
23225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (values.containsKey(RawContacts.ACCOUNT_TYPE)
23235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    || values.containsKey(RawContacts.ACCOUNT_NAME)
23245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    || values.containsKey(RawContacts.SOURCE_ID)) {
23255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                triggerAggregation(rawContactId);
23265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
2327433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey
2328433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey            if (values.containsKey(RawContacts.STARRED)) {
2329433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey                mContactAggregator.updateStarred(mDb, selectionWithId, selectionArgs);
2330433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey            }
2331285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            if (values.containsKey(RawContacts.SOURCE_ID)) {
2332285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateLookupKey(mDb, rawContactId);
2333285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
23345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
23355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return count;
233633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
233733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
2338321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    private int updateData(Uri uri, ContentValues values, String selection,
233973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            String[] selectionArgs, boolean markRawContactAsDirty) {
234020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.clear();
234120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.putAll(values);
234220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data._ID);
23435ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mValues.remove(Data.RAW_CONTACT_ID);
234420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
234520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
234620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        String packageName = values.getAsString(Data.RES_PACKAGE);
234720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        if (packageName != null) {
234820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.remove(Data.RES_PACKAGE);
234920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
235020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
235120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
235270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsSuperPrimary = mValues.containsKey(Data.IS_SUPER_PRIMARY);
235370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsPrimary = mValues.containsKey(Data.IS_PRIMARY);
235420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
235520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // Remove primary or super primary values being set to 0. This is disallowed by the
235620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // content provider.
235770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsSuperPrimary && mValues.getAsInteger(Data.IS_SUPER_PRIMARY) == 0) {
235820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsSuperPrimary = false;
235970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_SUPER_PRIMARY);
236020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
236170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsPrimary && mValues.getAsInteger(Data.IS_PRIMARY) == 0) {
236220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsPrimary = false;
236370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_PRIMARY);
236420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
236520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2366653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        int count = 0;
236720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2368653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
2369653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        // so we don't need to worry about updating data we don't have permission to read.
237014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(uri, DataUpdateQuery.COLUMNS, selection, selectionArgs, null);
2371653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        try {
2372653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            while(c.moveToNext()) {
2373653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                count += updateData(mValues, c, markRawContactAsDirty);
237420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
2375653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        } finally {
2376653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            c.close();
237720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
237820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2379653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        return count;
238020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
238120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2382653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    private int updateData(ContentValues values, Cursor c, boolean markRawContactAsDirty) {
2383653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        if (values.size() == 0) {
2384653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return 0;
2385321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        }
2386653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
238714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        final String mimeType = c.getString(DataUpdateQuery.MIMETYPE);
2388a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        DataRowHandler rowHandler = getDataRowHandler(mimeType);
2389a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        rowHandler.update(mDb, values, c, markRawContactAsDirty);
23908e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
2391a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        if (rowHandler.isAggregationRequired()) {
2392a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            triggerAggregation(rawContactId);
2393a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
23948e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
2395653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        return 1;
2396321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    }
2397321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana
2398de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    private int updateContactData(long contactId, ContentValues values) {
2399d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
2400d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // First update all constituent contacts
2401f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        ContentValues optionValues = new ContentValues(5);
24026cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyStringValue(optionValues, RawContacts.CUSTOM_RINGTONE,
2403d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.CUSTOM_RINGTONE);
24046cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.SEND_TO_VOICEMAIL,
2405d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.SEND_TO_VOICEMAIL);
24066cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.LAST_TIME_CONTACTED,
2407d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.LAST_TIME_CONTACTED);
24086cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.TIMES_CONTACTED,
2409d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.TIMES_CONTACTED);
24106cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.STARRED,
2411d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.STARRED);
2412d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
2413d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // Nothing to update - just return
2414d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        if (optionValues.size() == 0) {
2415d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov            return 0;
2416d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        }
2417d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
2418c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey        if (optionValues.containsKey(RawContacts.STARRED)) {
2419c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey            // Mark dirty when changing starred to trigger sync
2420c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey            optionValues.put(RawContacts.DIRTY, 1);
2421c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey        }
2422c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey
2423de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mDb.update(Tables.RAW_CONTACTS, optionValues,
2424d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                RawContacts.CONTACT_ID + "=" + contactId, null);
2425de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return mDb.update(Tables.CONTACTS, values, Contacts._ID + "=" + contactId, null);
2426f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
2427d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
2428d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    public void updateContactTime(long contactId, long lastTimeContacted) {
2429f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        mLastTimeContactedUpdate.bindLong(1, lastTimeContacted);
2430d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        mLastTimeContactedUpdate.bindLong(2, contactId);
2431f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        mLastTimeContactedUpdate.execute();
2432d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov    }
2433d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
24345ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static class RawContactPair {
24355ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        final long rawContactId1;
24365ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        final long rawContactId2;
2437127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
2438127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        /**
24395ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov         * Constructor that ensures that this.rawContactId1 &lt; this.rawContactId2
2440127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov         */
24415ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public RawContactPair(long rawContactId1, long rawContactId2) {
24425ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            if (rawContactId1 < rawContactId2) {
24435ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId1 = rawContactId1;
24445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId2 = rawContactId2;
2445127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            } else {
24465ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId2 = rawContactId1;
24475ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId1 = rawContactId2;
2448127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            }
2449127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        }
2450127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov    }
245180c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
2452127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov    private int updateAggregationException(SQLiteDatabase db, ContentValues values) {
2453127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        int exceptionType = values.getAsInteger(AggregationExceptions.TYPE);
2454d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        long contactId = values.getAsInteger(AggregationExceptions.CONTACT_ID);
24555ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        long rawContactId = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID);
245680c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
24573cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        // First, we build a list of rawContactID-rawContactID pairs for the given contact.
24585ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        ArrayList<RawContactPair> pairs = new ArrayList<RawContactPair>();
2459d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        Cursor c = db.query(ContactsQuery.TABLE, ContactsQuery.PROJECTION, RawContacts.CONTACT_ID
2460d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + "=" + contactId, null, null, null, null);
2461127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        try {
2462127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            while (c.moveToNext()) {
24635ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long aggregatedContactId = c.getLong(ContactsQuery.RAW_CONTACT_ID);
24645ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                if (aggregatedContactId != rawContactId) {
24655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    pairs.add(new RawContactPair(aggregatedContactId, rawContactId));
2466e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov                }
2467b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
2468b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        } finally {
2469b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            c.close();
2470b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        }
2471127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
2472127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // Now we iterate through all contact pairs to see if we need to insert/delete/update
2473127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // the corresponding exception
2474127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        ContentValues exceptionValues = new ContentValues(3);
2475127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        exceptionValues.put(AggregationExceptions.TYPE, exceptionType);
24765ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        for (RawContactPair pair : pairs) {
2477127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            final String whereClause =
24785ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    AggregationExceptionColumns.RAW_CONTACT_ID1 + "=" + pair.rawContactId1 + " AND "
24795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + AggregationExceptionColumns.RAW_CONTACT_ID2 + "=" + pair.rawContactId2;
2480127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) {
2481127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                db.delete(Tables.AGGREGATION_EXCEPTIONS, whereClause, null);
2482127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            } else {
24835ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                exceptionValues.put(AggregationExceptionColumns.RAW_CONTACT_ID1, pair.rawContactId1);
24845ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                exceptionValues.put(AggregationExceptionColumns.RAW_CONTACT_ID2, pair.rawContactId2);
2485127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID,
2486127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                        exceptionValues);
2487127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            }
2488127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        }
2489127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
2490421782cb554e5050cf62a86b98df6520038dcd15Dmitri Plotnikov        mContactAggregator.markForAggregation(rawContactId);
24918e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        mContactAggregator.aggregateContact(db, rawContactId,
24928e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                mOpenHelper.getContactId(rawContactId));
24938e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC
24948e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                || exceptionType == AggregationExceptions.TYPE_KEEP_OUT) {
24958e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            mContactAggregator.updateAggregateData(contactId);
24967a39bf269294a8130ddd463460b9b36cf4ff74a8Dmitri Plotnikov        }
2497127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
2498127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // The return value is fake - we just confirm that we made a change, not count actual
2499127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // rows changed.
2500127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        return 1;
2501b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    }
2502b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
2503619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2504619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
2505619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Test if a {@link String} value appears in the given list, and add to the
2506619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * array if the value doesn't already appear.
2507619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
2508619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private String[] assertContained(String[] array, String value) {
2509ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        if (array != null && !mOpenHelper.isInProjection(array, value)) {
2510619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            String[] newArray = new String[array.length + 1];
2511619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            System.arraycopy(array, 0, newArray, 0, array.length);
2512619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            newArray[array.length] = value;
2513619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            array = newArray;
2514619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
2515619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        return array;
2516619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
2517619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
25184f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
25194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
25204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            String sortOrder) {
25210b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov
25224f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
252335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2524d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
25251f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String groupBy = null;
2526c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limit = getLimit(uri);
2527c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2528619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // TODO: Consider writing a test case for RestrictionExceptions when you
2529619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // write a new query() block to make sure it protects restricted data.
2530a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
25314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
253235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
253335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                return mOpenHelper.getSyncState().query(db, projection, selection,  selectionArgs,
253435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                        sortOrder);
253535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2536d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
2537ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
2538619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                break;
2539619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            }
2540619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2541d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
25424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
2543ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
25444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Contacts._ID + "=" + contactId);
25456bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
25466bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
25476bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
25485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            case CONTACTS_LOOKUP:
25495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            case CONTACTS_LOOKUP_ID: {
25505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                List<String> pathSegments = uri.getPathSegments();
25515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int segmentCount = pathSegments.size();
25525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segmentCount < 3) {
25535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    throw new IllegalArgumentException("URI " + uri + " is missing a lookup key");
25545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
25555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String lookupKey = pathSegments.get(2);
25565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segmentCount == 4) {
25575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    long contactId = Long.parseLong(pathSegments.get(3));
25585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder();
25595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    setTablesAndProjectionMapForContacts(lookupQb, projection);
25605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    lookupQb.appendWhere(Contacts._ID + "=" + contactId + " AND " +
25615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            Contacts.LOOKUP_KEY + "=");
25625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    lookupQb.appendWhereEscapeString(lookupKey);
25635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    Cursor c = query(db, lookupQb, projection, selection, selectionArgs, sortOrder,
25645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            groupBy, limit);
25655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (c.getCount() != 0) {
25665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        return c;
25675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
25685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
25695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    c.close();
25705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
25715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
25725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
25735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                qb.appendWhere(Contacts._ID + "=" + lookupContactIdByLookupKey(db, lookupKey));
25745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                break;
25755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
25765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
2577ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_FILTER: {
2578ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
2579ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
25804a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
25814a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
2582e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    sb.append(Contacts._ID + " IN ");
2583e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    appendContactByFilterAsNestedQuery(sb, filterParam);
25844a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(sb.toString());
2585ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
2586ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2587ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2588ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
2589ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_STREQUENT_FILTER:
2590ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_STREQUENT: {
25914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                String filterSql = null;
2592ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                if (match == CONTACTS_STREQUENT_FILTER
2593d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        && uri.getPathSegments().size() > 3) {
25944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
25954a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
2596e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    sb.append(Contacts._ID + " IN ");
2597e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    appendContactByFilterAsNestedQuery(sb, filterParam);
25984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    filterSql = sb.toString();
25994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
26004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
2601ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
2602ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
26034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                // Build the first query for starred
26044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
26054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
2606d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2607d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                final String starredQuery = qb.buildQuery(projection, Contacts.STARRED + "=1",
26084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
2609d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2610d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Build the second query for frequent
2611d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                qb = new SQLiteQueryBuilder();
2612ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
26134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
26144a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
2615d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2616d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String frequentQuery = qb.buildQuery(projection,
2617d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        Contacts.TIMES_CONTACTED + " > 0 AND (" + Contacts.STARRED
2618d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        + " = 0 OR " + Contacts.STARRED + " IS NULL)",
26194a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
2620d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2621d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Put them together
2622d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery},
2623d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        STREQUENT_ORDER_BY, STREQUENT_LIMIT);
26244a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                Cursor c = db.rawQuery(query, null);
26254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (c != null) {
2626d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                    c.setNotificationUri(getContext().getContentResolver(),
2627d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                            ContactsContract.AUTHORITY_URI);
2628d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2629d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                return c;
2630d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar            }
2631d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2632ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_GROUP: {
2633ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                setTablesAndProjectionMapForContacts(qb, projection);
2634b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                if (uri.getPathSegments().size() > 2) {
26354a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(sContactsInGroupSelect);
26364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
2637b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                }
2638b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                break;
2639b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            }
2640b67163a1088f09c59f324350662eb18772fac6b6Evan Millar
2641d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_DATA: {
26424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
26434a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
26444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
26474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=" + contactId);
26486bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
26496bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
265000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
2651ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_PHOTO: {
26523653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
26533653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
26543653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26553653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26563653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
26573653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=" + contactId);
26583653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID);
26593653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                break;
26603653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov            }
26613653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
26624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case PHONES: {
26634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
26662815f58f72f109790585931f601a63ddc02536a5Evan Millar                break;
26672815f58f72f109790585931f601a63ddc02536a5Evan Millar            }
26682815f58f72f109790585931f601a63ddc02536a5Evan Millar
2669ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case PHONES_FILTER: {
26704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
2672ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                qb.appendWhere(Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
2673ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
26744a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
26754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
26764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    sb.append(Data.RAW_CONTACT_ID + " IN ");
26774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    appendRawContactsByFilterAsNestedQuery(sb, filterParam, null);
26784a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(" AND " + sb);
2679ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
2680ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2681ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2682ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
26834a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case EMAILS: {
26844a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
26874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                break;
26884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            }
26894a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
26904a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case EMAILS_FILTER: {
26914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
26924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
26934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
26944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (uri.getPathSegments().size() > 2) {
26954a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(" AND " + CommonDataKinds.Email.DATA + "=");
26964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhereEscapeString(uri.getLastPathSegment());
26974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
2698ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2699ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2700ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
2701ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case POSTALS: {
27024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
27034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
27044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + StructuredPostal.CONTENT_ITEM_TYPE + "'");
2705ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2706ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2707ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
27085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
27094a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getRawContactView());
2710d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sRawContactsProjectionMap);
27114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
27124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
27134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
27145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
27155ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
27164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getRawContactView());
2717d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sRawContactsProjectionMap);
27184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(RawContacts._ID + "=" + rawContactId);
27194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
27204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
27214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
27225ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
27235ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = Long.parseLong(uri.getPathSegments().get(1));
27244a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
27254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
27264a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.RAW_CONTACT_ID + "=" + rawContactId);
2727e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
2728e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
2729e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
2730e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            case DATA: {
27314a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
27324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
27334a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
2734e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
2735e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
2736e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
27374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            case DATA_ID: {
27384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
27394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
27404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data._ID + "=" + ContentUris.parseId(uri));
27414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
27424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
27434f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
2744a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov            case DATA_WITH_PRESENCE: {
2745a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov                qb.setTables(mOpenHelper.getDataView() + " data"
2746e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + " LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE
2747e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                        + " ON (" + AggregatedPresenceColumns.CONTACT_ID + "="
2748e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                                + RawContacts.CONTACT_ID + ")");
2749a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov                qb.setProjectionMap(sDataWithPresenceProjectionMap);
2750a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov                break;
2751a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov            }
2752a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov
2753a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case PHONE_LOOKUP: {
27544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
2755a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                if (TextUtils.isEmpty(sortOrder)) {
2756a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // Default the sort order to something reasonable so we get consistent
2757a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // results when callers don't request an ordering
2758e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                    sortOrder = RawContactsColumns.CONCRETE_ID;
2759a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                }
2760a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2761e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : "";
2762e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                mOpenHelper.buildPhoneLookupAndContactQuery(qb, number);
2763e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                qb.setProjectionMap(sPhoneLookupProjectionMap);
2764e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov
2765e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                // Phone lookup cannot be combined with a selection
2766e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                selection = null;
2767e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                selectionArgs = null;
2768a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
2769a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
2770a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2771ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
2772ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2773ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
2774ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2775ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2776ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2777ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
2778ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
2779ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2780ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
2781ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.appendWhere(GroupsColumns.CONCRETE_ID + "=" + groupId);
2782ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2783ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2784ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2785ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_SUMMARY: {
278699a9b5ec879f6cd6876f7f6b680b82d8304e6b92Dmitri Plotnikov                qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2787ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsSummaryProjectionMap);
2788ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                groupBy = GroupsColumns.CONCRETE_ID;
2789ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2790ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2791ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2792b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
27935ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.setTables(Tables.AGGREGATION_EXCEPTIONS_JOIN_RAW_CONTACTS);
2794b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                qb.setProjectionMap(sAggregationExceptionsProjectionMap);
2795b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
2796b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
2797b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
279831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_SUGGESTIONS: {
2799d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
280031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                final int maxSuggestions;
2801d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                if (limit != null) {
2802d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                    maxSuggestions = Integer.parseInt(limit);
280331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                } else {
280431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                    maxSuggestions = DEFAULT_MAX_SUGGESTIONS;
280531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                }
280631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
2807d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                return mContactAggregator.queryAggregationSuggestions(contactId, projection,
2808d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        sContactsProjectionMap, maxSuggestions);
280931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
281031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
2811eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
2812eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                qb.setTables(Tables.SETTINGS);
2813eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                qb.setProjectionMap(sSettingsProjectionMap);
2814e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
2815e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                // When requesting specific columns, this query requires
2816e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                // late-binding of the GroupMembership MIME-type.
2817e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                final String groupMembershipMimetypeId = Long.toString(mOpenHelper
2818e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                        .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE));
2819ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                if (mOpenHelper.isInProjection(projection, Settings.UNGROUPED_COUNT)) {
2820e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                    selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId);
2821e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                }
2822ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                if (mOpenHelper.isInProjection(projection, Settings.UNGROUPED_WITH_PHONES)) {
2823e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                    selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId);
2824e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                }
2825e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
2826eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
2827eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
2828eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
28295ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case PRESENCE: {
2830373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setTables(Tables.PRESENCE);
2831373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setProjectionMap(sPresenceProjectionMap);
28325ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
28335ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
28345ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
28355ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case PRESENCE_ID: {
2836373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setTables(Tables.PRESENCE);
2837373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setProjectionMap(sPresenceProjectionMap);
2838373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.appendWhere(Presence._ID + "=" + ContentUris.parseId(uri));
28395ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
28405ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
28415ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
2842c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS: {
2843a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov                return mGlobalSearchSupport.handleSearchSuggestionsQuery(db, uri, limit);
2844c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
2845c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2846c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT: {
2847b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
2848b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                return mGlobalSearchSupport.handleSearchShortcutRefresh(db, contactId, projection);
2849c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
2850c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
28511b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS:
28521b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
28531b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
28541b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
28551b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
28561b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_WITH_PHONES:
28571b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
28581b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
28591b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1");
28601b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
28611b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
28621b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_FAVORITES:
28631b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
28641b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
28651b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(Contacts.STARRED + "=1");
28661b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
28671b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
28681b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_GROUP_NAME:
28691b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
28701b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
28711b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(sContactsInGroupSelect);
28721b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
28731b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
28741b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
28754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            default:
2876f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.query(uri, projection, selection, selectionArgs,
2877c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                        sortOrder, limit);
28784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
28794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
28805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit);
28815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
28825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
28835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection,
28845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            String selection, String[] selectionArgs, String sortOrder, String groupBy,
28855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            String limit) {
2886038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        if (projection != null && projection.length == 1
2887038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana                && BaseColumns._COUNT.equals(projection[0])) {
2888038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            qb.setProjectionMap(sCountProjectionMap);
2889038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        }
28905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null,
28915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sortOrder, limit);
28924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        if (c != null) {
28934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI);
28944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
28954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        return c;
28964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
28974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
28985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) {
28995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        ContactLookupKey key = new ContactLookupKey();
29005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        ArrayList<LookupKeySegment> segments = key.parse(lookupKey);
29015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long contactId = lookupContactIdBySourceIds(db, segments);
29035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (contactId == -1) {
29045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            contactId = lookupContactIdByDisplayNames(db, segments);
29055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
29065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return contactId;
29085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
29095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private interface LookupBySourceIdQuery {
29115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String TABLE = Tables.RAW_CONTACTS;
29125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String COLUMNS[] = {
29145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.CONTACT_ID,
29155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
29165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
29175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.SOURCE_ID
29185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        };
29195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int CONTACT_ID = 0;
29215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_TYPE = 1;
29225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_NAME = 2;
29235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int SOURCE_ID = 3;
29245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
29255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdBySourceIds(SQLiteDatabase db,
29275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                ArrayList<LookupKeySegment> segments) {
29285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int sourceIdCount = 0;
29295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
29305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
29315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.sourceIdLookup) {
29325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sourceIdCount++;
29335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
29345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
29355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (sourceIdCount == 0) {
29375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return -1;
29385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
29395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        // First try sync ids
29415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
29425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(RawContacts.SOURCE_ID + " IN (");
29435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
29445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
29455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.sourceIdLookup) {
29465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(sb, segment.key);
29475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sb.append(",");
29485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
29495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
29505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.setLength(sb.length() - 1);      // Last comma
29515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL");
29525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS,
29545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                 sb.toString(), null, null, null, null);
29555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        try {
29565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            while (c.moveToNext()) {
29575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountType = c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE);
29585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME);
29595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int accountHashCode =
29605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        ContactLookupKey.getAccountHashCode(accountType, accountName);
29615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID);
29625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                for (int i = 0; i < segments.size(); i++) {
29635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    LookupKeySegment segment = segments.get(i);
29645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (segment.sourceIdLookup && accountHashCode == segment.accountHashCode
29655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            && segment.key.equals(sourceId)) {
29665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID);
29675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        break;
29685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
29695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
29705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
29715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } finally {
29725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            c.close();
29735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
29745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return getMostReferencedContactId(segments);
29765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
29775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private interface LookupByDisplayNameQuery {
29795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS;
29805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String COLUMNS[] = {
29825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.CONTACT_ID,
29835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
29845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
29855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                NameLookupColumns.NORMALIZED_NAME
29865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        };
29875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int CONTACT_ID = 0;
29895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_TYPE = 1;
29905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_NAME = 2;
29915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int NORMALIZED_NAME = 3;
29925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
29935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
29945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdByDisplayNames(SQLiteDatabase db,
29955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                ArrayList<LookupKeySegment> segments) {
29965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int displayNameCount = 0;
29975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
29985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
29995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (!segment.sourceIdLookup) {
30005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                displayNameCount++;
30015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
30025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
30035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (displayNameCount == 0) {
30055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return -1;
30065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
30075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        // First try sync ids
30095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
30105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(NameLookupColumns.NORMALIZED_NAME + " IN (");
30115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
30125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
30135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (!segment.sourceIdLookup) {
30145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(sb, segment.key);
30155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sb.append(",");
30165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
30175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
30185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.setLength(sb.length() - 1);      // Last comma
30195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY
30205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                + " AND " + RawContacts.CONTACT_ID + " NOT NULL");
30215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS,
30235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                 sb.toString(), null, null, null, null);
30245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        try {
30255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            while (c.moveToNext()) {
30265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountType = c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE);
30275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME);
30285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int accountHashCode =
30295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        ContactLookupKey.getAccountHashCode(accountType, accountName);
30305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME);
30315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                for (int i = 0; i < segments.size(); i++) {
30325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    LookupKeySegment segment = segments.get(i);
30335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (!segment.sourceIdLookup && accountHashCode == segment.accountHashCode
30345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            && segment.key.equals(name)) {
30355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID);
30365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        break;
30375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
30385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
30395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
30405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } finally {
30415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            c.close();
30425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
30435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return getMostReferencedContactId(segments);
30455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
30465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    /**
30485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov     * Returns the contact ID that is mentioned the highest number of times.
30495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov     */
30505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) {
30515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Collections.sort(segments);
30525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long bestContactId = -1;
30545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int bestRefCount = 0;
30555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long contactId = -1;
30575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int count = 0;
30585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
30595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int segmentCount = segments.size();
30605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segmentCount; i++) {
30615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
30625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.contactId != -1) {
30635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segment.contactId == contactId) {
30645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    count++;
30655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                } else {
30665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (count > bestRefCount) {
30675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        bestContactId = contactId;
30685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        bestRefCount = count;
30695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
30705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    contactId = segment.contactId;
30715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    count = 1;
30725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
30735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
30745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
30755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (count > bestRefCount) {
30765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return contactId;
30775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } else {
30785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return bestContactId;
30795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
30805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
30815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
3082ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, String[] projection) {
3083ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        String contactView = mOpenHelper.getContactView();
3084ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        boolean needsPresence = mOpenHelper.isInProjection(projection, Contacts.PRESENCE_STATUS,
3085ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                Contacts.PRESENCE_CUSTOM_STATUS);
3086ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        if (!needsPresence) {
3087ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            qb.setTables(contactView);
3088ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            qb.setProjectionMap(sContactsProjectionMap);
3089ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        } else {
3090ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            qb.setTables(contactView + " LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE + " ON ("
3091ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                    + Contacts._ID + " = " + AggregatedPresenceColumns.CONTACT_ID + ") ");
3092ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            qb.setProjectionMap(sContactsWithPresenceProjectionMap);
3093ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
3094ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        }
3095ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    }
3096ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
30974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) {
30984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
30994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
31004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (!TextUtils.isEmpty(accountName)) {
31014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
31024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountName) + " AND "
31034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + RawContacts.ACCOUNT_TYPE + "="
31044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountType));
31054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        } else {
31064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere("1");
31074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        }
31084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    }
31094a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
3110e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong    private String appendAccountToSelection(Uri uri, String selection) {
3111e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
3112e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
3113e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        if (!TextUtils.isEmpty(accountName)) {
3114e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "="
3115e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + DatabaseUtils.sqlEscapeString(accountName) + " AND "
3116e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + RawContacts.ACCOUNT_TYPE + "="
3117e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + DatabaseUtils.sqlEscapeString(accountType));
3118e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            if (!TextUtils.isEmpty(selection)) {
3119e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(" AND (");
3120e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(selection);
3121e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(')');
3122e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            }
3123e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            return selectionSb.toString();
3124e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        } else {
3125e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            return selection;
3126e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        }
3127e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong    }
3128e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong
31297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
3130c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * Gets the value of the "limit" URI query parameter.
3131c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *
3132c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * @return A string containing a non-negative integer, or <code>null</code> if
3133c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *         the parameter is not set, or is set to an invalid value.
3134c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     */
3135c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private String getLimit(Uri url) {
3136c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limitParam = url.getQueryParameter("limit");
3137c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limitParam == null) {
3138c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
3139c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
3140c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        // make sure that the limit is a non-negative integer
3141c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        try {
3142c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            int l = Integer.parseInt(limitParam);
3143c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            if (l < 0) {
3144c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                Log.w(TAG, "Invalid limit parameter: " + limitParam);
3145c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return null;
3146c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
3147c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return String.valueOf(l);
3148c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        } catch (NumberFormatException ex) {
3149c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            Log.w(TAG, "Invalid limit parameter: " + limitParam);
3150c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
3151c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
3152c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
3153c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
315400ec508630251d6c6e3746469c9428f5a8cd5996Jeff Sharkey    String getContactsRestrictions() {
31554a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (mOpenHelper.hasRestrictedAccess()) {
315670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
315770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        } else {
31586cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            return RawContacts.IS_RESTRICTED + "=0";
315970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
316070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    }
316170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
316270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    public String getContactsRestrictionExceptionAsNestedQuery(String contactIdColumn) {
31634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (mOpenHelper.hasRestrictedAccess()) {
316470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
316567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        } else {
31665ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return "(SELECT " + RawContacts.IS_RESTRICTED + " FROM " + Tables.RAW_CONTACTS
31675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + " WHERE " + RawContactsColumns.CONCRETE_ID + "=" + contactIdColumn + ")=0";
3168619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
3169619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
3170619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
3171b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    @Override
3172b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
3173b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        int match = sUriMatcher.match(uri);
3174b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        switch (match) {
3175b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov            case CONTACTS_PHOTO:
3176b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                if (!"r".equals(mode)) {
3177b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                    throw new FileNotFoundException("Mode " + mode + " not supported.");
3178b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                }
3179b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3180b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
3181b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3182b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                String sql =
3183b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                        "SELECT " + Photo.PHOTO + " FROM " + mOpenHelper.getDataView() +
3184b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                        " WHERE " + Data._ID + "=" + Contacts.PHOTO_ID
3185b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                                + " AND " + RawContacts.CONTACT_ID + "=" + contactId;
3186b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                SQLiteDatabase db = mOpenHelper.getReadableDatabase();
3187b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                return SQLiteContentHelper.getBlobColumnAsAssetFile(db, sql, null);
3188b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3189b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov            default:
3190b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov                throw new FileNotFoundException("No file at: " + uri);
3191b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        }
3192b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    }
3193b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3194b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3195b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
3196619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
31977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     * An implementation of EntityIterator that joins the contacts and data tables
31987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     * and consumes all the data rows for a contact in order to build the Entity for a contact.
31997e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
32007e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    private static class ContactsEntityIterator implements EntityIterator {
32017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private final Cursor mEntityCursor;
32027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private volatile boolean mIsClosed;
32037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private static final String[] DATA_KEYS = new String[]{
32057a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA1,
32067a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA2,
32077a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA3,
32087a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA4,
32097a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA5,
32107a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA6,
32117a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA7,
32127a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA8,
32137a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA9,
32147a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA10,
32157a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA11,
32167a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA12,
32177a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA13,
32187a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA14,
32197a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA15,
32207a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC1,
32217a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC2,
32227a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC3,
32237a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC4};
32247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private static final String[] PROJECTION = new String[]{
32266cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.ACCOUNT_NAME,
32276cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
32286cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.SOURCE_ID,
32296cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.VERSION,
32306cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.DIRTY,
32317a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data._ID,
32327a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.RES_PACKAGE,
32337a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.MIMETYPE,
32347a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA1,
32357a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA2,
32367a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA3,
32377a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA4,
32387a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA5,
32397a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA6,
32407a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA7,
32417a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA8,
32427a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA9,
32437a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA10,
32447a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA11,
32457a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA12,
32467a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA13,
32477a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA14,
32487a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA15,
32497a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC1,
32507a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC2,
32517a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC3,
32527a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC4,
32537a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.RAW_CONTACT_ID,
32547a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.IS_PRIMARY,
32553cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar                Data.IS_SUPER_PRIMARY,
32567a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA_VERSION,
32577a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                GroupMembership.GROUP_SOURCE_ID,
32587a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC1,
32597a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC2,
32607a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC3,
326194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                RawContacts.SYNC4,
326238446bf47c5ee2080df69f5fc8a33ad2fa3e61b5Jeff Sharkey                RawContacts.DELETED,
3263c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey                RawContacts.CONTACT_ID,
3264c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey                RawContacts.STARRED};
3265035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana
3266035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_ACCOUNT_NAME = 0;
3267035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_ACCOUNT_TYPE = 1;
3268035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_SOURCE_ID = 2;
3269035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_VERSION = 3;
3270035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_DIRTY = 4;
3271035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_DATA_ID = 5;
327267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_RES_PACKAGE = 6;
327367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_MIMETYPE = 7;
327467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_DATA1 = 8;
32757a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_RAW_CONTACT_ID = 27;
32767a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_IS_PRIMARY = 28;
32773cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_IS_SUPER_PRIMARY = 29;
32783cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_DATA_VERSION = 30;
32793cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_GROUP_SOURCE_ID = 31;
32803cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_SYNC1 = 32;
32813cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_SYNC2 = 33;
32823cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_SYNC3 = 34;
32833cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_SYNC4 = 35;
32843cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_DELETED = 36;
32853cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_CONTACT_ID = 37;
32863cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar        private static final int COLUMN_STARRED = 38;
32877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public ContactsEntityIterator(ContactsProvider2 provider, String contactsIdString, Uri uri,
32897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                String selection, String[] selectionArgs, String sortOrder) {
32907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mIsClosed = false;
32917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final String updatedSortOrder = (sortOrder == null)
32937a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                    ? Data.RAW_CONTACT_ID
32947a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                    : (Data.RAW_CONTACT_ID + "," + sortOrder);
32957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
32967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase();
32977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
3298226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setTables(Tables.CONTACT_ENTITIES);
32997e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (contactsIdString != null) {
33005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.appendWhere(Data.RAW_CONTACT_ID + "=" + contactsIdString);
33017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
33026cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
33036cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
3304035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            if (!TextUtils.isEmpty(accountName)) {
33056cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
3306035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                        + DatabaseUtils.sqlEscapeString(accountName) + " AND "
33076cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                        + RawContacts.ACCOUNT_TYPE + "="
3308035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                        + DatabaseUtils.sqlEscapeString(accountType));
3309035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            }
33107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs,
33117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    null, null, updatedSortOrder);
33127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor.moveToFirst();
33137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
33147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
3315038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        public void reset() throws RemoteException {
3316038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            if (mIsClosed) {
3317038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana                throw new IllegalStateException("calling reset() when the iterator is closed");
3318038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            }
3319038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            mEntityCursor.moveToFirst();
3320038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        }
3321038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana
33227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public void close() {
33237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
33247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("closing when already closed");
33257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
33267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mIsClosed = true;
33277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor.close();
33287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
33297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public boolean hasNext() throws RemoteException {
33317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
33327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("calling hasNext() when the iterator is closed");
33337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
33347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return !mEntityCursor.isAfterLast();
33367e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
33377e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33387e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public Entity next() throws RemoteException {
33397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
33407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("calling next() when the iterator is closed");
33417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
33427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (!hasNext()) {
33437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("you may only call next() if hasNext() is true");
33447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
33457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteCursor c = (SQLiteCursor) mEntityCursor;
33477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33487a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            final long rawContactId = c.getLong(COLUMN_RAW_CONTACT_ID);
33497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            // we expect the cursor is already at the row we need to read from
33517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            ContentValues contactValues = new ContentValues();
33526cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME));
33536cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE));
33545ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            contactValues.put(RawContacts._ID, rawContactId);
33556cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.DIRTY, c.getLong(COLUMN_DIRTY));
33566cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.VERSION, c.getLong(COLUMN_VERSION));
33576cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.SOURCE_ID, c.getString(COLUMN_SOURCE_ID));
33587a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC1, c.getString(COLUMN_SYNC1));
33597a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC2, c.getString(COLUMN_SYNC2));
33607a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC3, c.getString(COLUMN_SYNC3));
33617a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC4, c.getString(COLUMN_SYNC4));
336294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            contactValues.put(RawContacts.DELETED, c.getLong(COLUMN_DELETED));
336338446bf47c5ee2080df69f5fc8a33ad2fa3e61b5Jeff Sharkey            contactValues.put(RawContacts.CONTACT_ID, c.getLong(COLUMN_CONTACT_ID));
3364c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey            contactValues.put(RawContacts.STARRED, c.getLong(COLUMN_STARRED));
33657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            Entity contact = new Entity(contactValues);
33667e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
33677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            // read data rows until the contact id changes
33687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            do {
33697a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                if (rawContactId != c.getLong(COLUMN_RAW_CONTACT_ID)) {
33707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    break;
33717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
33727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                // add the data to to the contact
33737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                ContentValues dataValues = new ContentValues();
33747a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data._ID, c.getString(COLUMN_DATA_ID));
33757a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.RES_PACKAGE, c.getString(COLUMN_RES_PACKAGE));
33767a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.MIMETYPE, c.getString(COLUMN_MIMETYPE));
33777a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.IS_PRIMARY, c.getString(COLUMN_IS_PRIMARY));
33783cb415e7b97c3e318d7a16aaf7cc5c6b825d349aEvan Millar                dataValues.put(Data.IS_SUPER_PRIMARY, c.getString(COLUMN_IS_SUPER_PRIMARY));
33797a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION));
33809261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (!c.isNull(COLUMN_GROUP_SOURCE_ID)) {
33819261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    dataValues.put(GroupMembership.GROUP_SOURCE_ID,
33829261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            c.getString(COLUMN_GROUP_SOURCE_ID));
33839261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
33847a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION));
33857a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                for (int i = 0; i < DATA_KEYS.length; i++) {
33867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    final int columnIndex = i + COLUMN_DATA1;
33877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    String key = DATA_KEYS[i];
33887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    if (c.isNull(columnIndex)) {
33897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        // don't put anything
33907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isLong(columnIndex)) {
33917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getLong(columnIndex));
33927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isFloat(columnIndex)) {
33937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getFloat(columnIndex));
33947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isString(columnIndex)) {
33957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getString(columnIndex));
33967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isBlob(columnIndex)) {
33977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getBlob(columnIndex));
33987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    }
33997e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
34007e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                contact.addSubValue(Data.CONTENT_URI, dataValues);
34017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            } while (mEntityCursor.moveToNext());
34027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
34037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return contact;
34047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
34057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
34067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
3407226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    /**
3408226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     * An implementation of EntityIterator that joins the contacts and data tables
3409226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     * and consumes all the data rows for a contact in order to build the Entity for a contact.
3410226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     */
3411226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    private static class GroupsEntityIterator implements EntityIterator {
3412226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private final Cursor mEntityCursor;
3413226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private volatile boolean mIsClosed;
3414226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3415226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final String[] PROJECTION = new String[]{
3416226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups._ID,
3417226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.ACCOUNT_NAME,
3418226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.ACCOUNT_TYPE,
3419226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.SOURCE_ID,
3420226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.DIRTY,
3421226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.VERSION,
3422226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.RES_PACKAGE,
3423226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.TITLE,
3424226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.TITLE_RES,
34257a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.GROUP_VISIBLE,
34267a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC1,
34277a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC2,
34287a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC3,
34297a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC4,
34307a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYSTEM_ID,
343194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                Groups.NOTES,
343294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                Groups.DELETED};
3433226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3434226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ID = 0;
3435226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ACCOUNT_NAME = 1;
3436226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ACCOUNT_TYPE = 2;
3437226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_SOURCE_ID = 3;
3438226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_DIRTY = 4;
3439226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_VERSION = 5;
3440226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_RES_PACKAGE = 6;
3441226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_TITLE = 7;
3442226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_TITLE_RES = 8;
3443226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_GROUP_VISIBLE = 9;
34447a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC1 = 10;
34457a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC2 = 11;
34467a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC3 = 12;
34477a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC4 = 13;
34487a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYSTEM_ID = 14;
34497a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_NOTES = 15;
345094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        private static final int COLUMN_DELETED = 16;
3451226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3452226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public GroupsEntityIterator(ContactsProvider2 provider, String groupIdString, Uri uri,
3453226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                String selection, String[] selectionArgs, String sortOrder) {
3454226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mIsClosed = false;
3455226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3456226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String updatedSortOrder = (sortOrder == null)
3457226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    ? Groups._ID
3458226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    : (Groups._ID + "," + sortOrder);
3459226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3460226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase();
3461226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
3462226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
3463226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setProjectionMap(sGroupsProjectionMap);
3464226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (groupIdString != null) {
3465226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                qb.appendWhere(Groups._ID + "=" + groupIdString);
3466226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3467226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String accountName = uri.getQueryParameter(Groups.ACCOUNT_NAME);
3468226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String accountType = uri.getQueryParameter(Groups.ACCOUNT_TYPE);
3469226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (!TextUtils.isEmpty(accountName)) {
3470226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                qb.appendWhere(Groups.ACCOUNT_NAME + "="
3471226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + DatabaseUtils.sqlEscapeString(accountName) + " AND "
3472226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + Groups.ACCOUNT_TYPE + "="
3473226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + DatabaseUtils.sqlEscapeString(accountType));
3474226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3475226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs,
3476226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    null, null, updatedSortOrder);
3477226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.moveToFirst();
3478226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
3479226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3480226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public void close() {
3481226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
3482226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("closing when already closed");
3483226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3484226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mIsClosed = true;
3485226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.close();
3486226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
3487226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3488226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public boolean hasNext() throws RemoteException {
3489226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
3490226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("calling hasNext() when the iterator is closed");
3491226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3492226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3493226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            return !mEntityCursor.isAfterLast();
3494226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
3495226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3496038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        public void reset() throws RemoteException {
3497038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            if (mIsClosed) {
3498038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana                throw new IllegalStateException("calling reset() when the iterator is closed");
3499038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            }
3500038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            mEntityCursor.moveToFirst();
3501038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        }
3502e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
3503226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public Entity next() throws RemoteException {
3504226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
3505226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("calling next() when the iterator is closed");
3506226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3507226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (!hasNext()) {
3508226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("you may only call next() if hasNext() is true");
3509226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
3510226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3511226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteCursor c = (SQLiteCursor) mEntityCursor;
3512226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3513226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final long groupId = c.getLong(COLUMN_ID);
3514226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3515226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            // we expect the cursor is already at the row we need to read from
3516226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            ContentValues groupValues = new ContentValues();
3517226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME));
3518226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE));
3519226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups._ID, groupId);
3520226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.DIRTY, c.getLong(COLUMN_DIRTY));
3521226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.VERSION, c.getLong(COLUMN_VERSION));
3522226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.SOURCE_ID, c.getString(COLUMN_SOURCE_ID));
3523226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.RES_PACKAGE, c.getString(COLUMN_RES_PACKAGE));
3524226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.TITLE, c.getString(COLUMN_TITLE));
3525226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.TITLE_RES, c.getString(COLUMN_TITLE_RES));
3526226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.GROUP_VISIBLE, c.getLong(COLUMN_GROUP_VISIBLE));
35277a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC1, c.getString(COLUMN_SYNC1));
35287a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC2, c.getString(COLUMN_SYNC2));
35297a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC3, c.getString(COLUMN_SYNC3));
35307a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC4, c.getString(COLUMN_SYNC4));
35317a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYSTEM_ID, c.getString(COLUMN_SYSTEM_ID));
353294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            groupValues.put(Groups.DELETED, c.getLong(COLUMN_DELETED));
35337a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.NOTES, c.getString(COLUMN_NOTES));
3534226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            Entity group = new Entity(groupValues);
3535226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3536226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.moveToNext();
3537226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3538226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            return group;
3539226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
3540226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    }
3541226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3542a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    @Override
35437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
35447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            String sortOrder) {
3545568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
3546568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
35477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        final int match = sUriMatcher.match(uri);
35487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        switch (match) {
35495ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS:
35505ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID:
35517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                String contactsIdString = null;
35525ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                if (match == RAW_CONTACTS_ID) {
35537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    contactsIdString = uri.getPathSegments().get(1);
35547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
35557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
35567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                return new ContactsEntityIterator(this, contactsIdString,
35577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        uri, selection, selectionArgs, sortOrder);
3558226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            case GROUPS:
3559226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            case GROUPS_ID:
3560226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                String idString = null;
3561226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                if (match == GROUPS_ID) {
3562226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    idString = uri.getPathSegments().get(1);
3563226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                }
3564226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
3565226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                return new GroupsEntityIterator(this, idString,
3566226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        uri, selection, selectionArgs, sortOrder);
35677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            default:
35687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new UnsupportedOperationException("Unknown uri: " + uri);
35697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
35707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
35717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
35724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
35734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public String getType(Uri uri) {
3574a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
35754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
3576b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS:
3577b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS_LOOKUP:
3578be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov                return Contacts.CONTENT_TYPE;
3579b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS_ID:
3580b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS_LOOKUP_ID:
3581b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Contacts.CONTENT_ITEM_TYPE;
3582b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case RAW_CONTACTS:
3583be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov                return RawContacts.CONTENT_TYPE;
3584b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case RAW_CONTACTS_ID:
3585b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return RawContacts.CONTENT_ITEM_TYPE;
3586508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            case DATA_ID:
3587b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return mOpenHelper.getDataMimeType(ContentUris.parseId(uri));
3588b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_EXCEPTIONS:
3589b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return AggregationExceptions.CONTENT_TYPE;
3590b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_EXCEPTION_ID:
3591b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return AggregationExceptions.CONTENT_ITEM_TYPE;
3592b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case SETTINGS:
3593b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Settings.CONTENT_TYPE;
3594b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_SUGGESTIONS:
3595b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Contacts.CONTENT_TYPE;
3596c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS:
3597c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SUGGEST_MIME_TYPE;
3598c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT:
3599c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SHORTCUT_MIME_TYPE;
360061efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov            default:
360161efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov                return mLegacyApiSupport.getType(uri);
36024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
36034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
36047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
360525abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov    private void setDisplayName(long rawContactId, String displayName, int bestDisplayNameSource) {
36063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (displayName != null) {
360725abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            mRawContactDisplayNameUpdate.bindString(1, displayName);
36083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        } else {
360925abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov            mRawContactDisplayNameUpdate.bindNull(1);
36103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
361125abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        mRawContactDisplayNameUpdate.bindLong(2, bestDisplayNameSource);
361225abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        mRawContactDisplayNameUpdate.bindLong(3, rawContactId);
361325abcf949c0dd826a770b437489b83de48975ceaDmitri Plotnikov        mRawContactDisplayNameUpdate.execute();
36143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
36153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
361673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /**
361773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Checks the {@link Data#MARK_AS_DIRTY} query parameter.
361873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     *
361973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Returns true if the parameter is missing or is either "true" or "1".
362073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     */
362173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private boolean shouldMarkRawContactAsDirty(Uri uri) {
362273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (mImportMode) {
362373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            return false;
362473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
362573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
362673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        String param = uri.getQueryParameter(Data.MARK_AS_DIRTY);
362773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        return param == null || (!param.equalsIgnoreCase("false") && !param.equals("0"));
362873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    }
362973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
363073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /**
363173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Sets the {@link RawContacts#DIRTY} for the specified raw contact.
363273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     */
363373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private void setRawContactDirty(long rawContactId) {
363473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate.bindLong(1, rawContactId);
363573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate.execute();
363673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    }
363773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
363873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /**
363973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Checks the {@link Groups#MARK_AS_DIRTY} query parameter.
364073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     *
364173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Returns true if the parameter is missing or is either "true" or "1".
364273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     */
364373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private boolean shouldMarkGroupAsDirty(Uri uri) {
364473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (mImportMode) {
364573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            return false;
364673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
364773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
36482971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana        return readBooleanQueryParameter(uri, Groups.MARK_AS_DIRTY, true);
364973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    }
365073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
3651c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
3652c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to primary, and resets all data records of
3653c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * the same mimetype and under the same contact to not be primary.
3654c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
3655c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
3656c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
3657653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    private void setIsPrimary(long rawContactId, long dataId, long mimeTypeId) {
3658c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.bindLong(1, dataId);
3659653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetPrimaryStatement.bindLong(2, mimeTypeId);
3660653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetPrimaryStatement.bindLong(3, rawContactId);
3661c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.execute();
3662c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
3663c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
3664c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
3665c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to "super primary", and resets all data
3666c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * records of the same mimetype and under the same aggregate to not be "super primary".
3667c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
3668c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
3669c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
3670653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    private void setIsSuperPrimary(long rawContactId, long dataId, long mimeTypeId) {
3671c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.bindLong(1, dataId);
3672653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetSuperPrimaryStatement.bindLong(2, mimeTypeId);
3673653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        mSetSuperPrimaryStatement.bindLong(3, rawContactId);
3674c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.execute();
3675c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
3676ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
3677e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    private void appendContactByFilterAsNestedQuery(StringBuilder sb, String filterParam) {
3678e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        sb.append("(SELECT DISTINCT " + RawContacts.CONTACT_ID + " FROM " + Tables.RAW_CONTACTS
3679e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                + " JOIN name_lookup ON(" + RawContactsColumns.CONCRETE_ID + "=raw_contact_id)"
3680e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                + " WHERE normalized_name GLOB '");
3681e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        sb.append(NameNormalizer.normalize(filterParam));
3682e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        sb.append("*')");
3683e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    }
3684e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
36855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public String getRawContactsByFilterAsNestedQuery(String filterParam) {
3686c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        StringBuilder sb = new StringBuilder();
3687c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        appendRawContactsByFilterAsNestedQuery(sb, filterParam, null);
3688c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        return sb.toString();
3689c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
3690c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
3691a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    public void appendRawContactsByFilterAsNestedQuery(StringBuilder sb, String filterParam,
3692c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            String limit) {
3693c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append("(SELECT DISTINCT raw_contact_id FROM name_lookup WHERE normalized_name GLOB '");
3694c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append(NameNormalizer.normalize(filterParam));
3695c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append("*'");
3696c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limit != null) {
3697c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            sb.append(" LIMIT ").append(limit);
3698c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
3699c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append(")");
3700ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    }
3701ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
37024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /**
37034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     * Inserts an argument at the beginning of the selection arg list.
37044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     */
37054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private String[] insertSelectionArg(String[] selectionArgs, String arg) {
3706b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        if (selectionArgs == null) {
3707b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return new String[] {arg};
3708b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        } else {
3709b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            int newLength = selectionArgs.length + 1;
3710b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            String[] newSelectionArgs = new String[newLength];
37114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            newSelectionArgs[0] = arg;
37124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length);
3713b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return newSelectionArgs;
3714b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        }
3715b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    }
3716caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
3717caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    protected Account getDefaultAccount() {
3718caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        AccountManager accountManager = AccountManager.get(getContext());
3719caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        try {
3720df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana            Account[] accounts = accountManager.getAccountsByTypeAndFeatures(DEFAULT_ACCOUNT_TYPE,
3721df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                    new String[] {FEATURE_LEGACY_HOSTED_OR_GOOGLE}, null, null).getResult();
3722caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            if (accounts != null && accounts.length > 0) {
3723caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov                return accounts[0];
3724caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            }
3725caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        } catch (Throwable e) {
37266f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov            Log.e(TAG, "Cannot determine the default account for contacts compatibility", e);
3727caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        }
37286f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov        return null;
3729caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    }
37304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton}
3731