ContactsProvider2.java revision 013a0d6b3d392fb49d4618f2527b2ed3fec7d34f
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;
2028f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.AggregationExceptionColumns;
2128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.Clauses;
22d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.ContactsColumns;
2328f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.DataColumns;
2428f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.GroupsColumns;
2528f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.MimetypesColumns;
2611944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.NameLookupColumns;
2767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport com.android.providers.contacts.OpenHelper.PackagesColumns;
28d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.PhoneColumns;
2928f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.PhoneLookupColumns;
30d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.RawContactsColumns;
3128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.Tables;
32e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikovimport com.google.android.collect.Lists;
33e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
34b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account;
35caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikovimport android.accounts.AccountManager;
36c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager;
3735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris;
3867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues;
3967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context;
4035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.Entity;
4167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.EntityIterator;
423d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences;
4367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher;
443d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences.Editor;
454f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor;
46ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils;
47b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.database.sqlite.SQLiteCursor;
484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase;
494f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder;
50c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millarimport android.database.sqlite.SQLiteStatement;
514f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri;
52b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException;
533d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager;
54508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns;
55de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract;
563cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikovimport android.provider.Contacts.People;
57b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions;
58de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds;
59d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
60de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Data;
61ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.Groups;
621f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkeyimport android.provider.ContactsContract.Presence;
63d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.BaseTypes;
65ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Email;
66ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im;
683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname;
693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization;
70de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds.Phone;
714097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
7267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
73a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils;
74a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils;
75c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log;
764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList;
78b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap;
794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/**
814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications
824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}.
834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */
84de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikovpublic class ContactsProvider2 extends SQLiteContentProvider {
85caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
86b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    // TODO: clean up debug tag and rename this class
87b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private static final String TAG = "ContactsProvider ~~~~";
884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
89619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: carefully prevent all incoming nested queries; they can be gaping security holes
90619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: check for restricted flag during insert(), update(), and delete() calls
91619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Default for the maximum number of returned aggregation suggestions. */
933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DEFAULT_MAX_SUGGESTIONS = 5;
943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
953d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /**
963d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * Shared preference key for the legacy contact import version. The need for a version
973d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * as opposed to a boolean flag is that if we discover bugs in the contact import process,
983d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * we can trigger re-import by incrementing the import version.
993d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     */
1003d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private static final String PREF_CONTACTS_IMPORTED = "contacts_imported_v1";
1013d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private static final int PREF_CONTACTS_IMPORT_VERSION = 1;
1023d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
103a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
1044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
105d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, "
106d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.TIMES_CONTACTED + " DESC, "
107d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.DISPLAY_NAME + " ASC";
108d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar    private static final String STREQUENT_LIMIT =
109d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE "
110d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.STARRED + "=1) + 25";
111d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov
112d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS = 1000;
113d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS_ID = 1001;
114d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS_DATA = 1002;
115d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS_SUMMARY = 1003;
1162815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final int CONTACTS_SUMMARY_ID = 1005;
1172815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final int CONTACTS_SUMMARY_FILTER = 1006;
1182815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final int CONTACTS_SUMMARY_STREQUENT = 1007;
1192815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final int CONTACTS_SUMMARY_STREQUENT_FILTER = 1008;
1202815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final int CONTACTS_SUMMARY_GROUP = 1009;
1214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1225ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS = 2002;
1235ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_ID = 2003;
1245ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_DATA = 2004;
1254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1266bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA = 3000;
1276bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA_ID = 3001;
128ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int PHONES = 3002;
129ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int PHONES_FILTER = 3003;
1304a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final int EMAILS = 3004;
1314a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final int EMAILS_FILTER = 3005;
1324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final int POSTALS = 3006;
133a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1346bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int PHONE_LOOKUP = 4000;
1356bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
136b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTIONS = 6000;
137b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTION_ID = 6001;
138b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
1391f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    private static final int PRESENCE = 7000;
1401f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    private static final int PRESENCE_ID = 7001;
1411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
14231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    private static final int AGGREGATION_SUGGESTIONS = 8000;
14331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
144ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS = 10000;
145ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_ID = 10001;
146ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_SUMMARY = 10003;
147ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
14835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana    private static final int SYNCSTATE = 11000;
14935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
150c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SUGGESTIONS = 12001;
151c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SHORTCUT = 12002;
152c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
15367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    private interface ContactsQuery {
1545ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final String TABLE = Tables.RAW_CONTACTS;
1559261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
15667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
1576cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
1586cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.ACCOUNT_NAME,
1596cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.ACCOUNT_TYPE,
160ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
161ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1625ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
16367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int ACCOUNT_NAME = 1;
16467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int ACCOUNT_TYPE = 2;
16567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    }
16667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
167d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private interface DataRawContactsQuery {
1685ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final String TABLE = Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS;
16967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
17067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
1716cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
1723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
173d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            RawContacts.CONTACT_ID,
1746cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.IS_RESTRICTED,
1753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.MIMETYPE,
176ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
177ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1785ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
17967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA_ID = 1;
180d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int CONTACT_ID = 2;
18167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int IS_RESTRICTED = 3;
18267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int MIMETYPE = 4;
18367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    }
18467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
185d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private interface DataContactsQuery {
186d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS;
18767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
18867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
1896cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
1903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
191d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            ContactsColumns.CONCRETE_ID,
1923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.CONCRETE_ID,
193ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
194ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
195d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
19667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA_ID = 1;
197d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int CONTACT_ID = 2;
19867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int MIMETYPE_ID = 3;
199ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
2001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private interface DisplayNameQuery {
20267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
2033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final String[] COLUMNS = new String[] {
2053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
2063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
2073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA2,
2083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            StructuredName.DISPLAY_NAME,
2093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
2103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 0;
2123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 1;
2133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA2 = 2;
2143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DISPLAY_NAME = 3;
2153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
2163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private interface DataQuery {
21867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
2193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
22088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] CONCRETE_COLUMNS = new String[] {
2213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
2223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
2235ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Data.RAW_CONTACT_ID,
2243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
2253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA2,
22688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        };
22788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov
22888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] COLUMNS = new String[] {
22988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data._ID,
23088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            MimetypesColumns.MIMETYPE,
23188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.RAW_CONTACT_ID,
23288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.IS_PRIMARY,
23388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.DATA2,
2343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
2353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int ID = 0;
2373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 1;
2385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 2;
2393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 3;
24088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final int DATA2 = 4;
2413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
2423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
24320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private interface DataIdQuery {
244321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        String[] COLUMNS = { Data._ID, Data.RAW_CONTACT_ID, Data.MIMETYPE };
24520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
24620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int _ID = 0;
247321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int RAW_CONTACT_ID = 1;
248321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int MIMETYPE = 2;
24920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
25020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    // Higher number represents higher priority in choosing what data to use for the display name
2523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_EMAIL = 1;
2533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_PHONE = 2;
2543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_ORGANIZATION = 3;
2553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_STRUCTURED_NAME = 4;
2563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final HashMap<String, Integer> sDisplayNamePriorities;
2583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    static {
2593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities = new HashMap<String, Integer>();
2603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(StructuredName.CONTENT_ITEM_TYPE,
2613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_STRUCTURED_NAME);
2623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(Organization.CONTENT_ITEM_TYPE,
2633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_ORGANIZATION);
2643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(Phone.CONTENT_ITEM_TYPE,
2653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_PHONE);
2663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(Email.CONTENT_ITEM_TYPE,
2673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_EMAIL);
2683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
26931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
270caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    public static final String DEFAULT_ACCOUNT_TYPE = "com.google.GAIA";
271caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    public static final String FEATURE_APPS_FOR_DOMAIN = "google_or_dasher";
272caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
2734a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /** Contains just the contacts columns
2744a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     * @deprecated*/
2754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    @Deprecated
2764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final HashMap<String, String> sDeprecatedContactsProjectionMap;
2774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
2784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    private static final HashMap<String, String> sContactsProjectionMap;
2794a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
2804a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
281d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Contains the contact columns along with primary phone */
282d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final HashMap<String, String> sContactsSummaryProjectionMap;
283d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Contains just the contacts columns */
284d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final HashMap<String, String> sRawContactsProjectionMap;
2854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
2864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /**
2874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     * Contains just the contacts columns
2884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     *
2894a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     * @deprecated
2904a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     */
2914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    @Deprecated
2924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final HashMap<String, String> sDeprecatedRawContactsProjectionMap;
2934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
2944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /**
2954a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     * Contains just the data columns
2964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     *
2974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     * @deprecated
2984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     */
2994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    @Deprecated
3004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final HashMap<String, String> sDeprecatedDataGroupsProjectionMap;
3014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
3024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /** Contains columns from the data view */
3034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private static final HashMap<String, String> sDataProjectionMap;
3044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
3059261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /** Contains the data and contacts columns, for joined tables */
3060c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar    private static final HashMap<String, String> sDataRawContactsGroupsProjectionMap;
307a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /** Contains the data and contacts columns, for joined tables */
3080c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar    private static final HashMap<String, String> sDataRawContactsProjectionMap;
309ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains the just the {@link Groups} columns */
310ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsProjectionMap;
311ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains {@link Groups} columns along with summary details */
312ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsSummaryProjectionMap;
313373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    /** Contains the agg_exceptions columns */
314b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final HashMap<String, String> sAggregationExceptionsProjectionMap;
315373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    /** Contains Presence columns */
316373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    private static final HashMap<String, String> sPresenceProjectionMap;
3177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
318c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Sql select statement that returns the contact id associated with a data record. */
319d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String sNestedRawContactIdSelect;
320c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Sql select statement that returns the mimetype id associated with a data record. */
321c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private static final String sNestedMimetypeSelect;
322d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Sql select statement that returns the contact id associated with a contact record. */
323d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String sNestedContactIdSelect;
324d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Sql select statement that returns a list of contact ids associated with an contact record. */
325c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private static final String sNestedContactIdListSelect;
326c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Sql where statement used to match all the data records that need to be updated when a new
327c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * "primary" is selected.*/
328c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private static final String sSetPrimaryWhere;
329c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Sql where statement used to match all the data records that need to be updated when a new
330c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * "super primary" is selected.*/
331c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private static final String sSetSuperPrimaryWhere;
332b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    /** Sql where statement for filtering on groups. */
333d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String sContactsInGroupSelect;
334c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Precompiled sql statement for setting a data record to the primary. */
335c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetPrimaryStatement;
3363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for setting a data record to the super primary. */
337c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetSuperPrimaryStatement;
338d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Precompiled sql statement for incrementing times contacted for an contact */
339f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private SQLiteStatement mLastTimeContactedUpdate;
3403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for updating a contact display name */
3413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private SQLiteStatement mContactDisplayNameUpdate;
34273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /** Precompiled sql statement for marking a raw contact as dirty */
34373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private SQLiteStatement mRawContactDirtyUpdate;
344a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
3454f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    static {
3464f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        // Contacts URI matching table
347a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final UriMatcher matcher = sUriMatcher;
348d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS);
349d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
350d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_DATA);
351d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary", CONTACTS_SUMMARY);
352d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary/#", CONTACTS_SUMMARY_ID);
353d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary/filter/*",
354d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                CONTACTS_SUMMARY_FILTER);
355d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary/strequent/",
356d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                CONTACTS_SUMMARY_STREQUENT);
357d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary/strequent/filter/*",
358d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                CONTACTS_SUMMARY_STREQUENT_FILTER);
359d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary/group/*",
360d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                CONTACTS_SUMMARY_GROUP);
361d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions",
36231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                AGGREGATION_SUGGESTIONS);
3635ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
3645ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID);
3655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA);
366b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
3674f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);
3684f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID);
369ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES);
370ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER);
3714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS);
3724a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER);
373ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS);
3741f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
375ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS);
376ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID);
377ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY);
378ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
37935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE);
38035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
381a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP);
382b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions",
383b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTIONS);
384b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*",
385b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTION_ID);
3864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
387bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "presence", PRESENCE);
388bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "presence/#", PRESENCE_ID);
3891f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
390c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
391c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
392c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
393c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
394c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/#",
395c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SHORTCUT);
396c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
3974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap = new HashMap<String, String>();
3984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts._ID, Contacts._ID);
3994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME);
4004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
4014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
4024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
4034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.IN_VISIBLE_GROUP, Contacts.IN_VISIBLE_GROUP);
4044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
4054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
406f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov        sContactsProjectionMap.put(Contacts.HAS_PHONE_NUMBER, Contacts.HAS_PHONE_NUMBER);
4074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
4084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
4094a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsSummaryProjectionMap = new HashMap<String, String>();
4104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsSummaryProjectionMap.putAll(sContactsProjectionMap);
4114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsSummaryProjectionMap.put(Contacts.PRESENCE_STATUS,
4124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                "MAX(" + Presence.PRESENCE_STATUS + ") AS " + Contacts.PRESENCE_STATUS);
4134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
414fec4e13316f2731d84394e5fa2f93af3febdc20cEvan Millar        HashMap<String, String> columns;
4154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
416d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        // Contacts projection map
4176bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov        columns = new HashMap<String, String>();
418d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts._ID, "contacts._id AS _id");
419d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.DISPLAY_NAME, ContactsColumns.CONCRETE_DISPLAY_NAME + " AS "
420d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Contacts.DISPLAY_NAME);
421d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.LAST_TIME_CONTACTED, ContactsColumns.CONCRETE_LAST_TIME_CONTACTED
422d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " AS " + Contacts.LAST_TIME_CONTACTED);
423d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.TIMES_CONTACTED, ContactsColumns.CONCRETE_TIMES_CONTACTED + " AS "
424d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Contacts.TIMES_CONTACTED);
425d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.STARRED, ContactsColumns.CONCRETE_STARRED + " AS "
426d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Contacts.STARRED);
427d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.IN_VISIBLE_GROUP, Contacts.IN_VISIBLE_GROUP);
428d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
429d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.CUSTOM_RINGTONE, ContactsColumns.CONCRETE_CUSTOM_RINGTONE + " AS "
430d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Contacts.CUSTOM_RINGTONE);
431d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.SEND_TO_VOICEMAIL, ContactsColumns.CONCRETE_SEND_TO_VOICEMAIL
432d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " AS " + Contacts.SEND_TO_VOICEMAIL);
4334a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDeprecatedContactsProjectionMap = columns;
4346bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
4351f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        columns = new HashMap<String, String>();
4364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        columns.putAll(sDeprecatedContactsProjectionMap);
437c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov
4384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov//        // Contacts primaries projection map. The overall presence status is
4394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov//        // the most-present value, as indicated by the largest value.
4404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov//        columns.put(Contacts.PRESENCE_STATUS, "MAX(" + Presence.PRESENCE_STATUS + ") AS "
4414a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov//                + Contacts.PRESENCE_STATUS);
4424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov//        columns.put(Contacts.PRIMARY_PHONE_TYPE, CommonDataKinds.Phone.TYPE);
4434a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov//        columns.put(Contacts.PRIMARY_PHONE_LABEL, CommonDataKinds.Phone.LABEL);
4444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov//        columns.put(Contacts.PRIMARY_PHONE_NUMBER, CommonDataKinds.Phone.NUMBER);
4454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov//        sContactsSummaryProjectionMap = columns;
44600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
4476cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        // RawContacts projection map
4484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        columns = new HashMap<String, String>();
4495ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        columns.put(RawContacts._ID, Tables.RAW_CONTACTS + "." + RawContacts._ID + " AS _id");
450d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
4516cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        columns.put(RawContacts.ACCOUNT_NAME,
4525ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_ACCOUNT_NAME
4535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.ACCOUNT_NAME);
4546cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        columns.put(RawContacts.ACCOUNT_TYPE,
4555ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_ACCOUNT_TYPE
4565ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.ACCOUNT_TYPE);
4576cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        columns.put(RawContacts.SOURCE_ID,
4585ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_SOURCE_ID
4595ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.SOURCE_ID);
4606cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        columns.put(RawContacts.VERSION,
4615ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_VERSION
4625ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.VERSION);
4636cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        columns.put(RawContacts.DIRTY,
4645ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_DIRTY
4655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.DIRTY);
46633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        columns.put(RawContacts.DELETED,
4675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_DELETED
4685ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.DELETED);
4693cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(RawContacts.TIMES_CONTACTED,
4703cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                Tables.RAW_CONTACTS + "." + RawContacts.TIMES_CONTACTED
4713cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                        + " AS " + People.TIMES_CONTACTED);
4723cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(RawContacts.LAST_TIME_CONTACTED,
4733cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                Tables.RAW_CONTACTS + "." + RawContacts.LAST_TIME_CONTACTED
4743cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                        + " AS " + People.LAST_TIME_CONTACTED);
4753cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(RawContacts.CUSTOM_RINGTONE,
4763cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                Tables.RAW_CONTACTS + "." + RawContacts.CUSTOM_RINGTONE
4773cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                        + " AS " + People.CUSTOM_RINGTONE);
4783cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(RawContacts.SEND_TO_VOICEMAIL,
4793cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                Tables.RAW_CONTACTS + "." + RawContacts.SEND_TO_VOICEMAIL
4803cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                        + " AS " + People.SEND_TO_VOICEMAIL);
4813cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(RawContacts.STARRED,
4823cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                Tables.RAW_CONTACTS + "." + RawContacts.STARRED
4833cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                        + " AS " + People.STARRED);
4843cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE);
4853cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(RawContacts.SYNC1,
4863cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                Tables.RAW_CONTACTS + "." + RawContacts.SYNC1 + " AS " + RawContacts.SYNC1);
4873cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(RawContacts.SYNC2,
4883cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                Tables.RAW_CONTACTS + "." + RawContacts.SYNC2 + " AS " + RawContacts.SYNC2);
4893cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(RawContacts.SYNC3,
4903cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                Tables.RAW_CONTACTS + "." + RawContacts.SYNC3 + " AS " + RawContacts.SYNC3);
4913cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(RawContacts.SYNC4,
4923cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov                Tables.RAW_CONTACTS + "." + RawContacts.SYNC4 + " AS " + RawContacts.SYNC4);
4934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDeprecatedRawContactsProjectionMap = columns;
4944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
4954a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap = new HashMap<String, String>();
4964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts._ID, RawContacts._ID);
4974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
4984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
4994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
5004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
5014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.VERSION, RawContacts.VERSION);
5024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DIRTY, RawContacts.DIRTY);
5034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.DELETED, RawContacts.DELETED);
5044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.TIMES_CONTACTED, RawContacts.TIMES_CONTACTED);
5054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.LAST_TIME_CONTACTED,
5064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                RawContacts.LAST_TIME_CONTACTED);
5074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.CUSTOM_RINGTONE, RawContacts.CUSTOM_RINGTONE);
5084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SEND_TO_VOICEMAIL, RawContacts.SEND_TO_VOICEMAIL);
5094a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.STARRED, RawContacts.STARRED);
5104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE);
5114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC1, RawContacts.SYNC1);
5124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC2, RawContacts.SYNC2);
5134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC3, RawContacts.SYNC3);
5144a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sRawContactsProjectionMap.put(RawContacts.SYNC4, RawContacts.SYNC4);
5152815f58f72f109790585931f601a63ddc02536a5Evan Millar
5164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        // Data projection map
5174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        columns = new HashMap<String, String>();
5185ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        columns.put(Data._ID, Tables.DATA + "." + Data._ID + " AS _id");
5195ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        columns.put(Data.RAW_CONTACT_ID, Data.RAW_CONTACT_ID);
52067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.RES_PACKAGE, PackagesColumns.PACKAGE + " AS " + Data.RES_PACKAGE);
521508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        columns.put(Data.MIMETYPE, Data.MIMETYPE);
522c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        columns.put(Data.IS_PRIMARY, Data.IS_PRIMARY);
523c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        columns.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY);
524f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        columns.put(Data.DATA_VERSION, Data.DATA_VERSION);
5257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA1, "data.data1 as data1");
5267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA2, "data.data2 as data2");
5277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA3, "data.data3 as data3");
5287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA4, "data.data4 as data4");
5297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA5, "data.data5 as data5");
5307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA6, "data.data6 as data6");
5317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA7, "data.data7 as data7");
5327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA8, "data.data8 as data8");
5337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA9, "data.data9 as data9");
5347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA10, "data.data10 as data10");
53567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.DATA11, "data.data11 as data11");
53667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.DATA12, "data.data12 as data12");
53767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.DATA13, "data.data13 as data13");
53867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.DATA14, "data.data14 as data14");
53967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.DATA15, "data.data15 as data15");
5403cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Data.SYNC1, Tables.DATA + "." + Data.SYNC1 + " AS " + Data.SYNC1);
5413cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Data.SYNC2, Tables.DATA + "." + Data.SYNC2 + " AS " + Data.SYNC2);
5423cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Data.SYNC3, Tables.DATA + "." + Data.SYNC3 + " AS " + Data.SYNC3);
5433cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Data.SYNC4, Tables.DATA + "." + Data.SYNC4 + " AS " + Data.SYNC4);
54467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(GroupMembership.GROUP_SOURCE_ID, GroupsColumns.CONCRETE_SOURCE_ID + " AS "
54567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + GroupMembership.GROUP_SOURCE_ID);
54620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
54720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // TODO: remove this projection
548d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar        // Mappings used for backwards compatibility.
549d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar        columns.put("number", Phone.NUMBER);
5504a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDeprecatedDataGroupsProjectionMap = columns;
5514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
5524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap = new HashMap<String, String>();
5534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data._ID, Data._ID);
5544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.RAW_CONTACT_ID, Data.RAW_CONTACT_ID);
5554a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA_VERSION, Data.DATA_VERSION);
5564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.IS_PRIMARY, Data.IS_PRIMARY);
5574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY);
5584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.RES_PACKAGE, Data.RES_PACKAGE);
5594a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.MIMETYPE, Data.MIMETYPE);
5604a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA1, Data.DATA1);
5614a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA2, Data.DATA2);
5624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA3, Data.DATA3);
5634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA4, Data.DATA4);
5644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA5, Data.DATA5);
5654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA6, Data.DATA6);
5664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA7, Data.DATA7);
5674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA8, Data.DATA8);
5684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA9, Data.DATA9);
5694a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA10, Data.DATA10);
5704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA11, Data.DATA11);
5714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA12, Data.DATA12);
5724a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA13, Data.DATA13);
5734a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA14, Data.DATA14);
5744a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.DATA15, Data.DATA15);
5754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC1, Data.SYNC1);
5764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC2, Data.SYNC2);
5774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC3, Data.SYNC3);
5784a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Data.SYNC4, Data.SYNC4);
5794a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
5804a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
5814a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
5824a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
5834a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.VERSION, RawContacts.VERSION);
5844a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(RawContacts.DIRTY, RawContacts.DIRTY);
5854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.DISPLAY_NAME, Contacts.DISPLAY_NAME);
5864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
5874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
5884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
5894a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.TIMES_CONTACTED, Contacts.TIMES_CONTACTED);
5904a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.STARRED, Contacts.STARRED);
5914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
5924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sDataProjectionMap.put(GroupMembership.GROUP_SOURCE_ID, GroupMembership.GROUP_SOURCE_ID);
593a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
5949261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // Data, groups and contacts projection map for joins. _id comes from the data table
595a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        columns = new HashMap<String, String>();
5964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        columns.putAll(sDeprecatedRawContactsProjectionMap);
59799a9b5ec879f6cd6876f7f6b680b82d8304e6b92Dmitri Plotnikov        columns.putAll(sDeprecatedDataGroupsProjectionMap);
598d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Data.RAW_CONTACT_ID, DataColumns.CONCRETE_RAW_CONTACT_ID);
5990c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar        sDataRawContactsGroupsProjectionMap = columns;
6009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
6019261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // Data and contacts projection map for joins. _id comes from the data table
6029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns = new HashMap<String, String>();
6030c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar        columns.putAll(sDataRawContactsGroupsProjectionMap);
6049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.remove(GroupMembership.GROUP_SOURCE_ID);
6050c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar        sDataRawContactsProjectionMap = columns;
6067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
607ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Groups projection map
608ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
609ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups._ID, "groups._id AS _id");
610035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_NAME, Groups.ACCOUNT_NAME);
611035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_TYPE, Groups.ACCOUNT_TYPE);
6129261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.SOURCE_ID, Groups.SOURCE_ID);
6139261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.DIRTY, Groups.DIRTY);
6149261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.VERSION, Groups.VERSION);
61567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Groups.RES_PACKAGE, PackagesColumns.PACKAGE + " AS " + Groups.RES_PACKAGE);
616ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.TITLE, Groups.TITLE);
61767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Groups.TITLE_RES, Groups.TITLE_RES);
618ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.GROUP_VISIBLE, Groups.GROUP_VISIBLE);
6193cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYSTEM_ID, Groups.SYSTEM_ID);
62094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        columns.put(Groups.DELETED, Groups.DELETED);
6213cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.NOTES, Groups.NOTES);
6223cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC1, Tables.GROUPS + "." + Groups.SYNC1 + " AS " + Groups.SYNC1);
6233cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC2, Tables.GROUPS + "." + Groups.SYNC2 + " AS " + Groups.SYNC2);
6243cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC3, Tables.GROUPS + "." + Groups.SYNC3 + " AS " + Groups.SYNC3);
6253cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        columns.put(Groups.SYNC4, Tables.GROUPS + "." + Groups.SYNC4 + " AS " + Groups.SYNC4);
626ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsProjectionMap = columns;
627ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
6286cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        // RawContacts and groups projection map
629ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
630ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.putAll(sGroupsProjectionMap);
631ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
632d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Groups.SUMMARY_COUNT, "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID
633d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
634ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
635ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + ") AS " + Groups.SUMMARY_COUNT);
636ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
637ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.SUMMARY_WITH_PHONES, "(SELECT COUNT(DISTINCT "
638d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ContactsColumns.CONCRETE_ID + ") FROM "
639d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
640ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
641f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov                + " AND " + Contacts.HAS_PHONE_NUMBER + ") AS " + Groups.SUMMARY_WITH_PHONES);
642ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
643ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsSummaryProjectionMap = columns;
644ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
645b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        // Aggregate exception projection map
646b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns = new HashMap<String, String>();
647b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id AS _id");
648b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE);
649d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(AggregationExceptions.CONTACT_ID,
650d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                "raw_contacts1." + RawContacts.CONTACT_ID
651d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " AS " + AggregationExceptions.CONTACT_ID);
6525ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        columns.put(AggregationExceptions.RAW_CONTACT_ID, AggregationExceptionColumns.RAW_CONTACT_ID2);
653b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        sAggregationExceptionsProjectionMap = columns;
654b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
655373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov
656373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns = new HashMap<String, String>();
657373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence._ID, Presence._ID);
658373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.RAW_CONTACT_ID, Presence.RAW_CONTACT_ID);
659373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.DATA_ID, Presence.DATA_ID);
660373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.IM_ACCOUNT, Presence.IM_ACCOUNT);
661373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.IM_HANDLE, Presence.IM_HANDLE);
662373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.IM_PROTOCOL, Presence.IM_PROTOCOL);
663373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.PRESENCE_STATUS, Presence.PRESENCE_STATUS);
664373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.PRESENCE_CUSTOM_STATUS, Presence.PRESENCE_CUSTOM_STATUS);
665373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        sPresenceProjectionMap = columns;
666373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov
667d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        sNestedRawContactIdSelect = "SELECT " + Data.RAW_CONTACT_ID + " FROM " + Tables.DATA + " WHERE "
668c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + Data._ID + "=?";
669c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        sNestedMimetypeSelect = "SELECT " + DataColumns.MIMETYPE_ID + " FROM " + Tables.DATA
670c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + " WHERE " + Data._ID + "=?";
671d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        sNestedContactIdSelect = "SELECT " + RawContacts.CONTACT_ID + " FROM " + Tables.RAW_CONTACTS
672d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " WHERE " + RawContacts._ID + "=(" + sNestedRawContactIdSelect + ")";
6735ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        sNestedContactIdListSelect = "SELECT " + RawContacts._ID + " FROM " + Tables.RAW_CONTACTS
674d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " WHERE " + RawContacts.CONTACT_ID + "=(" + sNestedContactIdSelect + ")";
675d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        sSetPrimaryWhere = Data.RAW_CONTACT_ID + "=(" + sNestedRawContactIdSelect + ") AND "
676c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + DataColumns.MIMETYPE_ID + "=(" + sNestedMimetypeSelect + ")";
6775ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        sSetSuperPrimaryWhere = Data.RAW_CONTACT_ID + " IN (" + sNestedContactIdListSelect + ") AND "
678c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + DataColumns.MIMETYPE_ID + "=(" + sNestedMimetypeSelect + ")";
6794a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        sContactsInGroupSelect = Contacts._ID + " IN "
6804a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                + "(SELECT " + RawContacts.CONTACT_ID
6814a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                + " FROM " + Tables.RAW_CONTACTS
6824a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN "
6834a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID
6844a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        + " FROM " + Tables.DATA_JOIN_MIMETYPES
6854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE
6864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + "' AND " + GroupMembership.GROUP_ROW_ID + "="
6874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + "(SELECT " + Tables.GROUPS + "." + Groups._ID
6884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + " FROM " + Tables.GROUPS
6894a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                                + " WHERE " + Groups.TITLE + "=?)))";
6904f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
6914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
6923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /**
6933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     * Handles inserts and update for a specific Data type.
6943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     */
6953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private abstract class DataRowHandler {
6963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected final String mMimetype;
6983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public DataRowHandler(String mimetype) {
7003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mMimetype = mimetype;
7013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
7043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Inserts a row into the {@link Data} table.
7053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
7065ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
707e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            final long dataId = db.insert(Tables.DATA, null, values);
708e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
709e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            Integer primary = values.getAsInteger(Data.IS_PRIMARY);
710e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (primary != null && primary != 0) {
711e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                setIsPrimary(dataId);
712e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
713e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
7145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            fixContactDisplayName(db, rawContactId);
715e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return dataId;
7163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
7193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Validates data and updates a {@link Data} row using the cursor, which contains
7203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * the current data.
7213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
7223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor cursor) {
7233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            throw new UnsupportedOperationException();
7243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
7273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            long dataId = c.getLong(DataQuery.ID);
7285ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long rawContactId = c.getLong(DataQuery.RAW_CONTACT_ID);
7293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            boolean primary = c.getInt(DataQuery.IS_PRIMARY) != 0;
7303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            int count = db.delete(Tables.DATA, Data._ID + "=" + dataId, null);
7313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (count != 0 && primary) {
7325ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                fixPrimary(db, rawContactId);
7335ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                fixContactDisplayName(db, rawContactId);
7343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
7353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return count;
7363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        private void fixPrimary(SQLiteDatabase db, long rawContactId) {
7395ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long newPrimaryId = findNewPrimaryDataId(db, rawContactId);
7403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (newPrimaryId != -1) {
7413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                ContactsProvider2.this.setIsPrimary(newPrimaryId);
7423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
7433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected long findNewPrimaryDataId(SQLiteDatabase db, long rawContactId) {
746e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            long primaryId = -1;
747e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            int primaryType = -1;
7485ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Cursor c = queryData(db, rawContactId);
7493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
750e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                while (c.moveToNext()) {
751e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    long dataId = c.getLong(DataQuery.ID);
752e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    int type = c.getInt(DataQuery.DATA2);
753e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) {
754e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryId = dataId;
755e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryType = type;
756e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    }
7573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
7583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
7593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
7603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
761e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return primaryId;
762e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
763e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
764e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        /**
765e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * Returns the rank of a specific record type to be used in determining the primary
766e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * row. Lower number represents higher priority.
767e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         */
768e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
769e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return 0;
7703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7725ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected Cursor queryData(SQLiteDatabase db, long rawContactId) {
77388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            return db.query(DataQuery.TABLE, DataQuery.CONCRETE_COLUMNS, Data.RAW_CONTACT_ID + "="
7745ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + rawContactId + " AND " + MimetypesColumns.MIMETYPE + "='" + mMimetype + "'",
7753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    null, null, null, null);
7763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7785ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected void fixContactDisplayName(SQLiteDatabase db, long rawContactId) {
779e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (!sDisplayNamePriorities.containsKey(mMimetype)) {
780e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                return;
781e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
782e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
7833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String bestDisplayName = null;
78467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            Cursor c = db.query(DisplayNameQuery.TABLE, DisplayNameQuery.COLUMNS,
7855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    Data.RAW_CONTACT_ID + "=" + rawContactId, null, null, null, null);
7863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
7873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                int maxPriority = -1;
7883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                while (c.moveToNext()) {
7893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    String mimeType = c.getString(DisplayNameQuery.MIMETYPE);
7903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    boolean primary;
7913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    String name;
7923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
7943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        name = c.getString(DisplayNameQuery.DISPLAY_NAME);
7953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        primary = true;
7963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    } else {
7973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        name = c.getString(DisplayNameQuery.DATA2);
7983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        primary = (c.getInt(DisplayNameQuery.IS_PRIMARY) != 0);
7993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    }
8003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    if (primary && name != null) {
8023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        Integer priority = sDisplayNamePriorities.get(mimeType);
8033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        if (priority != null && priority > maxPriority) {
8043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                            maxPriority = priority;
8053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                            bestDisplayName = name;
8063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        }
8073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    }
8083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
8093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
8113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
8123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            ContactsProvider2.this.setDisplayName(rawContactId, bestDisplayName);
8153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
8173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CustomDataRowHandler extends DataRowHandler {
8193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CustomDataRowHandler(String mimetype) {
8213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
8223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
8243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class StructuredNameRowHandler extends DataRowHandler {
8263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final NameSplitter mNameSplitter;
8283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public StructuredNameRowHandler(NameSplitter nameSplitter) {
8303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(StructuredName.CONTENT_ITEM_TYPE);
8313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mNameSplitter = nameSplitter;
8323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
8355ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
8363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            fixStructuredNameComponents(values);
8375ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return super.insert(db, rawContactId, values);
8383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
8413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor cursor) {
8423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            // TODO Parse the full name if it has changed and replace pre-existing piece parts.
8433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
8463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Parses the supplied display name, but only if the incoming values do not already contain
8473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * structured name parts.  Also, if the display name is not provided, generate one by
8483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * concatenating first name and last name
8493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         *
8503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * TODO see if the order of first and last names needs to be conditionally reversed for
8513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * some locales, e.g. China.
8523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
8533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private void fixStructuredNameComponents(ContentValues values) {
8543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String fullName = values.getAsString(StructuredName.DISPLAY_NAME);
8553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (!TextUtils.isEmpty(fullName)
8563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.PREFIX))
8573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.GIVEN_NAME))
8583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.MIDDLE_NAME))
8593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.FAMILY_NAME))
8603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.SUFFIX))) {
8613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                NameSplitter.Name name = new NameSplitter.Name();
8623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                mNameSplitter.split(name, fullName);
8633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.PREFIX, name.getPrefix());
8653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.GIVEN_NAME, name.getGivenNames());
8663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.MIDDLE_NAME, name.getMiddleName());
8673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.FAMILY_NAME, name.getFamilyName());
8683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.SUFFIX, name.getSuffix());
8693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (TextUtils.isEmpty(fullName)) {
8723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                String givenName = values.getAsString(StructuredName.GIVEN_NAME);
8733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                String familyName = values.getAsString(StructuredName.FAMILY_NAME);
8743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                if (TextUtils.isEmpty(givenName)) {
8753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = familyName;
8763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                } else if (TextUtils.isEmpty(familyName)) {
8773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = givenName;
8783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                } else {
8793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = givenName + " " + familyName;
8803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
8813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                if (!TextUtils.isEmpty(fullName)) {
8833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    values.put(StructuredName.DISPLAY_NAME, fullName);
8843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
8853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
8883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CommonDataRowHandler extends DataRowHandler {
8903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mTypeColumn;
8923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mLabelColumn;
8933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CommonDataRowHandler(String mimetype, String typeColumn, String labelColumn) {
8953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
8963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mTypeColumn = typeColumn;
8973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mLabelColumn = labelColumn;
8983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
9015ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
9023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            int type;
9033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String label;
9043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (values.containsKey(mTypeColumn)) {
9053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                type = values.getAsInteger(mTypeColumn);
9063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } else {
9073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                type = BaseTypes.TYPE_CUSTOM;
9083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (values.containsKey(mLabelColumn)) {
9103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                label = values.getAsString(mLabelColumn);
9113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } else {
9123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                label = null;
9133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (type != BaseTypes.TYPE_CUSTOM && label != null) {
9167a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException(mLabelColumn + " value can only be specified with "
9173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        + mTypeColumn + "=" + BaseTypes.TYPE_CUSTOM + "(custom)");
9183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (type == BaseTypes.TYPE_CUSTOM && label == null) {
9217a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException(mLabelColumn + " value must be specified when "
9223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        + mTypeColumn + "=" + BaseTypes.TYPE_CUSTOM + "(custom)");
9233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9255ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return super.insert(db, rawContactId, values);
9263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
9293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor cursor) {
9303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            // TODO read the data and check the constraint
9313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
9333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class OrganizationDataRowHandler extends CommonDataRowHandler {
9353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public OrganizationDataRowHandler() {
9373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Organization.CONTENT_ITEM_TYPE, Organization.TYPE, Organization.LABEL);
9383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
9415ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
9425ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long id = super.insert(db, rawContactId, values);
9435ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            fixContactDisplayName(db, rawContactId);
9443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return id;
9453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
9483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
9493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
9503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_WORK: return 0;
9513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_CUSTOM: return 1;
9523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_OTHER: return 2;
9533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
9543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
9573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
958e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    public class EmailDataRowHandler extends CommonDataRowHandler {
959e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
960e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public EmailDataRowHandler() {
961e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            super(Email.CONTENT_ITEM_TYPE, Email.TYPE, Email.LABEL);
962e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
963e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
964e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
9655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
9665ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long id = super.insert(db, rawContactId, values);
9675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            fixContactDisplayName(db, rawContactId);
968e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return id;
969e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
970e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
971e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
972e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
973e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            switch (type) {
974e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_HOME: return 0;
975e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_WORK: return 1;
976e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_CUSTOM: return 2;
977e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_OTHER: return 3;
978e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                default: return 1000;
979e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
980e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
981e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    }
982e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
9833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class PhoneDataRowHandler extends CommonDataRowHandler {
9843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public PhoneDataRowHandler() {
9863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Phone.CONTENT_ITEM_TYPE, Phone.TYPE, Phone.LABEL);
9873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
9905ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
991e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            ContentValues phoneValues = new ContentValues();
992e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            String number = values.getAsString(Phone.NUMBER);
993e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            String normalizedNumber = null;
994e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (number != null) {
995e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                normalizedNumber = PhoneNumberUtils.getStrippedReversed(number);
996e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                values.put(PhoneColumns.NORMALIZED_NUMBER, normalizedNumber);
997e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
998e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
9995ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long id = super.insert(db, rawContactId, values);
10003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1001e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (number != null) {
10025ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.RAW_CONTACT_ID, rawContactId);
1003e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.DATA_ID, id);
1004e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, normalizedNumber);
1005e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                db.insert(Tables.PHONE_LOOKUP, null, phoneValues);
1006e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
10073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return id;
10093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
10103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
10123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
10133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
10143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_MOBILE: return 0;
10153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_WORK: return 1;
10163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_HOME: return 2;
10173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_PAGER: return 3;
10183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_CUSTOM: return 4;
10193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_OTHER: return 5;
10203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_WORK: return 6;
10213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_HOME: return 7;
10223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
10233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
10243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
10253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
10263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private HashMap<String, DataRowHandler> mDataRowHandlers;
102853056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov    private final ContactAggregationScheduler mAggregationScheduler;
10294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    private OpenHelper mOpenHelper;
103031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
1031a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    private ContactAggregator mContactAggregator;
10324097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov    private NameSplitter mNameSplitter;
1033f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private LegacyApiSupport mLegacyApiSupport;
1034a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    private GlobalSearchSupport mGlobalSearchSupport;
1035a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
103620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private ContentValues mValues = new ContentValues();
103720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
103873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private boolean mImportMode;
103973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1040de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    private boolean mScheduleAggregation;
1041de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov
1042a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    public ContactsProvider2() {
104353056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        this(new ContactAggregationScheduler());
1044a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1045a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1046a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
1047a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Constructor for testing.
1048a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
104953056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov    /* package */ ContactsProvider2(ContactAggregationScheduler scheduler) {
105053056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        mAggregationScheduler = scheduler;
1051a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
10524f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
10534f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
10544f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public boolean onCreate() {
1055de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        super.onCreate();
105635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1057de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final Context context = getContext();
1058de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mOpenHelper = (OpenHelper)getOpenHelper();
1059a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mGlobalSearchSupport = new GlobalSearchSupport(this);
1060a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mLegacyApiSupport = new LegacyApiSupport(context, mOpenHelper, this, mGlobalSearchSupport);
106153056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        mContactAggregator = new ContactAggregator(context, mOpenHelper, mAggregationScheduler);
1062a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1063d51a83ac4f8032b62d9a23b90a8f43d6b7eb2dbbDmitri Plotnikov        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1064c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement = db.compileStatement(
1065c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                "UPDATE " + Tables.DATA + " SET " + Data.IS_PRIMARY
1066c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + "=(_id=?) WHERE " + sSetPrimaryWhere);
1067c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement = db.compileStatement(
1068c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                "UPDATE " + Tables.DATA + " SET " + Data.IS_SUPER_PRIMARY
1069c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + "=(_id=?) WHERE " + sSetSuperPrimaryWhere);
10705ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mLastTimeContactedUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
10716cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                + RawContacts.TIMES_CONTACTED + "=" + RawContacts.TIMES_CONTACTED + "+1,"
1072d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + RawContacts.LAST_TIME_CONTACTED + "=? WHERE " + RawContacts.CONTACT_ID + "=?");
1073a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
10745ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mContactDisplayNameUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
10756cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                + RawContactsColumns.DISPLAY_NAME + "=? WHERE " + RawContacts._ID + "=?");
10763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
107773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
107873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                + RawContacts.DIRTY + "=1 WHERE " + RawContacts._ID + "=?");
107973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
108028f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar        mNameSplitter = new NameSplitter(
108128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_prefixes),
108228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_last_name_prefixes),
108328f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_suffixes),
108428f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_conjunctions));
10854097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
10863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers = new HashMap<String, DataRowHandler>();
10873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1088e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, new EmailDataRowHandler());
10893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE,
10903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new CommonDataRowHandler(Im.CONTENT_ITEM_TYPE, Im.TYPE, Im.LABEL));
109167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler(
109267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, StructuredPostal.LABEL));
10933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, new OrganizationDataRowHandler());
10943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, new PhoneDataRowHandler());
109567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler(
109667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE, Nickname.LABEL));
10973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE,
10983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new StructuredNameRowHandler(mNameSplitter));
10993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11003d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        if (isLegacyContactImportNeeded()) {
11013d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            if (!importLegacyContacts()) {
11023d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov                return false;
11033d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            }
11043d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
11051f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        return (db != null);
11064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
11074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
110831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    /* Visible for testing */
1109de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    @Override
111031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    protected OpenHelper getOpenHelper(final Context context) {
111131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov        return OpenHelper.getInstance(context);
111231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    }
111331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
1114013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    /* package */ NameSplitter getNameSplitter() {
1115013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov        return mNameSplitter;
1116013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    }
1117013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov
11183d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    protected boolean isLegacyContactImportNeeded() {
11193d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
11203d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        return prefs.getInt(PREF_CONTACTS_IMPORTED, 0) < PREF_CONTACTS_IMPORT_VERSION;
11213d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
11223d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
11233d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    private boolean importLegacyContacts() {
1124013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov        if (importLegacyContacts(getLegacyContactImporter(), true)) {
11253d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
11263d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            Editor editor = prefs.edit();
11273d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            editor.putInt(PREF_CONTACTS_IMPORTED, PREF_CONTACTS_IMPORT_VERSION);
11283d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            editor.commit();
11293d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return true;
11303d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        } else {
11313d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return false;
11323d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
11333d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
11343d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
11353d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    protected LegacyContactImporter getLegacyContactImporter() {
11363d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        return new LegacyContactImporter(getContext(), this);
11373d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
11383d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
11393d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /* Visible for testing */
1140013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    /* package */ boolean importLegacyContacts(LegacyContactImporter importer, boolean aggregate) {
11413d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        mContactAggregator.setEnabled(false);
114273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mImportMode = true;
11433d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        try {
11443d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            importer.importContacts();
11453d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            mContactAggregator.setEnabled(true);
1146013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov            if (aggregate) {
1147013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov                mContactAggregator.run();
1148013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov            }
11493d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            return true;
11503d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        } catch (Throwable e) {
11513d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov           Log.e(TAG, "Legacy contact import failed", e);
11523d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov           return false;
115373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        } finally {
115473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            mImportMode = false;
11553d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
11563d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
11573d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1158a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    @Override
1159a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    protected void finalize() throws Throwable {
1160a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        if (mContactAggregator != null) {
1161a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov            mContactAggregator.quit();
1162a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        }
1163a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1164a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        super.finalize();
1165a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1166a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1167a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
1168a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Wipes all data from the contacts database.
1169a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
1170a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /* package */ void wipeData() {
1171a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        mOpenHelper.wipeData();
1172a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1173a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
11744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
1175de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected void onTransactionComplete() {
1176de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (mScheduleAggregation) {
1177de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            mScheduleAggregation = false;
1178de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            mContactAggregator.schedule();
1179de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
1180de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        super.onTransactionComplete();
11814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
11824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
11833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private DataRowHandler getDataRowHandler(final String mimeType) {
11843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        DataRowHandler handler = mDataRowHandlers.get(mimeType);
11853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (handler == null) {
11863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            handler = new CustomDataRowHandler(mimeType);
11873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mDataRowHandlers.put(mimeType, handler);
11883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
11893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        return handler;
11903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
11913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
1193de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected Uri insertInTransaction(Uri uri, ContentValues values) {
1194a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
1195a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
119635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1197a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        switch (match) {
119835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
1199de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                id = mOpenHelper.getSyncState().insert(mDb, values);
120035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                break;
120135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1202d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
1203d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                insertContact(values);
12046bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
12056bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
12066bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
12075ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
1208f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                final Account account = readAccountFromQueryParams(uri);
1209d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                id = insertRawContact(values, account);
1210a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1211a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1212a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
12135ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
12145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1));
121573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                id = insertData(values, shouldMarkRawContactAsDirty(uri));
1216a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1217a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1218a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1219a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case DATA: {
122073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                id = insertData(values, shouldMarkRawContactAsDirty(uri));
1221a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1222a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1223a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1224ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
1225ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                final Account account = readAccountFromQueryParams(uri);
122673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                id = insertGroup(values, account, shouldMarkGroupAsDirty(uri));
1227ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
1228ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1229ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
12301f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            case PRESENCE: {
12311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                id = insertPresence(values);
12321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                break;
12331f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
12341f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
1235a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            default:
1236f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.insert(uri, values);
1237a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
1238a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
12397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        if (id < 0) {
12407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return null;
12417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
12427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
1243de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return ContentUris.withAppendedId(uri, id);
1244a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
1245a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1246a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
1247035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * If account is non-null then store it in the values. If the account is already
1248035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * specified in the values then it must be consistent with the account, if it is non-null.
1249035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @param values the ContentValues to read from and update
1250035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @param account the explicitly provided Account
1251035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @return false if the accounts are inconsistent
12527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
1253035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana    private boolean resolveAccount(ContentValues values, Account account) {
1254035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        // If either is specified then both must be specified.
12556cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
12566cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
1257035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        if (!TextUtils.isEmpty(accountName) || !TextUtils.isEmpty(accountType)) {
1258035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            final Account valuesAccount = new Account(accountName, accountType);
1259035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            if (account != null && !valuesAccount.equals(account)) {
1260035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                return false;
1261035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            }
1262035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            account = valuesAccount;
1263035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
1264035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        if (account != null) {
12656cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            values.put(RawContacts.ACCOUNT_NAME, account.mName);
12666cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            values.put(RawContacts.ACCOUNT_TYPE, account.mType);
1267035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
1268035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        return true;
12697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
12707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
12717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
1272d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov     * Inserts an item in the contacts table
12736bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     *
12746bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @param values the values for the new row
12756bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @return the row ID of the newly created row
12766bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     */
1277d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertContact(ContentValues values) {
1278de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        throw new UnsupportedOperationException("Aggregate contacts are created automatically");
12796bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    }
12806bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
12816bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    /**
1282a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the contacts table
1283a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
1284a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
1285f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana     * @param account the account this contact should be associated with. may be null.
1286a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
1287a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
1288d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertRawContact(ContentValues values, Account account) {
12896bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov        /*
12906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         * The contact record is inserted in the contacts table, but it needs to
12916bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         * be processed by the aggregator before it will be returned by the
12926bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         * "aggregates" queries.
12936bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         */
1294a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        ContentValues overriddenValues = new ContentValues(values);
1295d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        overriddenValues.putNull(RawContacts.CONTACT_ID);
1296f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        if (!resolveAccount(overriddenValues, account)) {
12977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return -1;
12987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
12997e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
13003d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        if (values.containsKey(RawContacts.DELETED)
13013d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov                && values.getAsInteger(RawContacts.DELETED) != 0) {
13023d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov            overriddenValues.put(RawContacts.AGGREGATION_MODE,
13033d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov                    RawContacts.AGGREGATION_MODE_DISABLED);
13043d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
13053d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1306de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return mDb.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, overriddenValues);
1307a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
1308a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1309a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
1310a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the data table
1311a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
1312a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
1313a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
1314a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
131573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private long insertData(ContentValues values, boolean markRawContactAsDirty) {
13166cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        int aggregationMode = RawContacts.AGGREGATION_MODE_DISABLED;
1317a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
1318de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.clear();
1319de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.putAll(values);
132067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
1321de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID);
132220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1323de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace package with internal mapping
1324de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String packageName = mValues.getAsString(Data.RES_PACKAGE);
1325de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (packageName != null) {
1326de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
1327de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
1328de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.RES_PACKAGE);
1329508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
1330de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace mimetype with internal mapping
1331de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String mimeType = mValues.getAsString(Data.MIMETYPE);
1332de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (TextUtils.isEmpty(mimeType)) {
1333de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            throw new IllegalArgumentException(Data.MIMETYPE + " is required");
1334de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
13354097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
1336de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.put(DataColumns.MIMETYPE_ID, mOpenHelper.getMimeTypeId(mimeType));
1337de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
1338a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1339de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // TODO create GroupMembershipRowHandler and move this code there
1340de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        resolveGroupSourceIdInValues(rawContactId, mimeType, mDb, mValues, true /* isInsert */);
1341a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1342de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        id = getDataRowHandler(mimeType).insert(mDb, rawContactId, mValues);
1343de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (markRawContactAsDirty) {
1344de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            setRawContactDirty(rawContactId);
1345a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
1346a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1347de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        aggregationMode = mContactAggregator.markContactForAggregation(mDb, rawContactId);
1348de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov
1349f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        triggerAggregation(id, aggregationMode);
1350a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        return id;
13514f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
13524f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
13535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private void triggerAggregation(long rawContactId, int aggregationMode) {
1354f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        switch (aggregationMode) {
13556cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DEFAULT:
1356de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                mScheduleAggregation = true;
1357f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
1358f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
13596cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_IMMEDITATE:
1360de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                mContactAggregator.aggregateContact(mDb, rawContactId);
1361f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
1362f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
13636cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DISABLED:
1364f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                // Do nothing
1365f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
1366f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        }
1367f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
1368f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
1369a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
13705ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * Returns the group id of the group with sourceId and the same account as rawContactId.
13719261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * If the group doesn't already exist then it is first created,
13729261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param db SQLiteDatabase to use for this operation
13735ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * @param rawContactId the contact this group is associated with
13749261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param sourceId the sourceIf of the group to query or create
13759261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @return the group id of the existing or created group
13769261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalArgumentException if the contact is not associated with an account
13779261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalStateException if a group needs to be created but the creation failed
13789261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     */
13795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private long getOrMakeGroup(SQLiteDatabase db, long rawContactId, String sourceId) {
13809261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        Account account = null;
13816cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Cursor c = db.query(ContactsQuery.TABLE, ContactsQuery.PROJECTION, RawContacts._ID + "="
13825ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                + rawContactId, null, null, null, null);
13839261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
13849261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            if (c.moveToNext()) {
138567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                final String accountName = c.getString(ContactsQuery.ACCOUNT_NAME);
138667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                final String accountType = c.getString(ContactsQuery.ACCOUNT_TYPE);
13879261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
13889261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    account = new Account(accountName, accountType);
13899261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
13909261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
13919261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
13929261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
13939261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
13949261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        if (account == null) {
13959261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            throw new IllegalArgumentException("if the groupmembership only "
13969261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "has a sourceid the the contact must be associate with "
13979261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "an account");
13989261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
13999261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
14009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // look up the group that contains this sourceId and has the same account name and type
14015ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        // as the contact refered to by rawContactId
14026cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        c = db.query(Tables.GROUPS, new String[]{RawContacts._ID},
14039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Clauses.GROUP_HAS_ACCOUNT_AND_SOURCE_ID,
14049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                new String[]{sourceId, account.mName, account.mType}, null, null, null);
14059261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
14069261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            if (c.moveToNext()) {
14079261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                return c.getLong(0);
14089261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            } else {
14099261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                ContentValues groupValues = new ContentValues();
14109261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                groupValues.put(Groups.ACCOUNT_NAME, account.mName);
14119261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                groupValues.put(Groups.ACCOUNT_TYPE, account.mType);
14129261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                groupValues.put(Groups.SOURCE_ID, sourceId);
14139261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                long groupId = db.insert(Tables.GROUPS, Groups.ACCOUNT_NAME, groupValues);
14149261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (groupId < 0) {
14159261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    throw new IllegalStateException("unable to create a new group with "
14169261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            + "this sourceid: " + groupValues);
14179261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
14189261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                return groupId;
14199261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
14209261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
14219261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
14229261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
14239261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    }
14249261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
14259261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /**
142620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     * Delete data row by row so that fixing of primaries etc work correctly.
142720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     */
142873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private int deleteData(String selection, String[] selectionArgs,
142973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            boolean markRawContactAsDirty) {
143020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int count = 0;
143120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1432de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
1433de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
143488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataQuery.COLUMNS, selection, selectionArgs, null);
1435de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        try {
1436de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            while(c.moveToNext()) {
143788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                long rawContactId = c.getLong(DataQuery.RAW_CONTACT_ID);
143888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                String mimeType = c.getString(DataQuery.MIMETYPE);
143988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                count += getDataRowHandler(mimeType).delete(mDb, c);
144088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                if (markRawContactAsDirty) {
144188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                    setRawContactDirty(rawContactId);
144288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                }
144320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
144420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
1445de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            c.close();
144620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
144720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
144820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        return count;
144920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
145020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
145188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov    /**
145288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     * Delete a data row provided that it is one of the allowed mime types.
145388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     */
145420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    public int deleteData(long dataId, String[] allowedMimeTypes) {
1455f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
145688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
145788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
145888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataQuery.COLUMNS, Data._ID + "=" + dataId, null, null);
1459f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
146020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        try {
146120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!c.moveToFirst()) {
146220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                return 0;
146320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
146420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
146520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            String mimeType = c.getString(DataQuery.MIMETYPE);
146620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            boolean valid = false;
146720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            for (int i = 0; i < allowedMimeTypes.length; i++) {
146820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                if (TextUtils.equals(mimeType, allowedMimeTypes[i])) {
146920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    valid = true;
147020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    break;
147120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                }
147220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
147320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
147420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!valid) {
14757a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException("Data type mismatch: expected "
147620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                        + Lists.newArrayList(allowedMimeTypes));
147720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
147820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
147988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            return getDataRowHandler(mimeType).delete(mDb, c);
148020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
148120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            c.close();
148220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
148320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
148420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
148520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    /**
1486ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Inserts an item in the groups table
1487ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
148873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private long insertGroup(ContentValues values, Account account, boolean markAsDirty) {
1489ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        ContentValues overriddenValues = new ContentValues(values);
1490ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        if (!resolveAccount(overriddenValues, account)) {
1491ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            return -1;
1492ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        }
1493ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1494ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Replace package with internal mapping
149567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        final String packageName = overriddenValues.getAsString(Groups.RES_PACKAGE);
149667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        if (packageName != null) {
149767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            overriddenValues.put(GroupsColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
149867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        }
149967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        overriddenValues.remove(Groups.RES_PACKAGE);
1500ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
150173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (markAsDirty) {
150273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            overriddenValues.put(Groups.DIRTY, 1);
150373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
150473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1505de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return mDb.insert(Tables.GROUPS, Groups.TITLE, overriddenValues);
1506ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
1507ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1508ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
15091f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     * Inserts a presence update.
15101f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     */
151170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    public long insertPresence(ContentValues values) {
15121f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        final String handle = values.getAsString(Presence.IM_HANDLE);
15131f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        final String protocol = values.getAsString(Presence.IM_PROTOCOL);
15141f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        if (TextUtils.isEmpty(handle) || TextUtils.isEmpty(protocol)) {
15151f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            throw new IllegalArgumentException("IM_PROTOCOL and IM_HANDLE are required");
15161f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
15171f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
15181f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        // TODO: generalize to allow other providers to match against email
1519a01e50cb1a5dd21293f8a8fe43f3fe0bf6349164Jeff Sharkey        boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == Integer.parseInt(protocol);
15201f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
152170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        StringBuilder selection = new StringBuilder();
15221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String[] selectionArgs;
15231f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        if (matchEmail) {
152470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            selection.append("(" + Clauses.WHERE_IM_MATCHES + ") OR ("
152570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                    + Clauses.WHERE_EMAIL_MATCHES + ")");
15261f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            selectionArgs = new String[] { protocol, handle, handle };
15271f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } else {
152870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            selection.append(Clauses.WHERE_IM_MATCHES);
15291f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            selectionArgs = new String[] { protocol, handle };
15301f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
15311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
153270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (values.containsKey(Presence.DATA_ID)) {
153370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            selection.append(" AND " + DataColumns.CONCRETE_ID + "=")
153470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                    .append(values.getAsLong(Presence.DATA_ID));
153570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
153670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
15375ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        if (values.containsKey(Presence.RAW_CONTACT_ID)) {
1538d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            selection.append(" AND " + DataColumns.CONCRETE_RAW_CONTACT_ID + "=")
15395ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    .append(values.getAsLong(Presence.RAW_CONTACT_ID));
154070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
154170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
154200ec508630251d6c6e3746469c9428f5a8cd5996Jeff Sharkey        selection.append(" AND ").append(getContactsRestrictions());
154370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
15441f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        long dataId = -1;
15455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        long rawContactId = -1;
154670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
15471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        Cursor cursor = null;
15481f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        try {
1549de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION,
155070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                    selection.toString(), selectionArgs, null, null, null);
15511f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            if (cursor.moveToFirst()) {
155267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                dataId = cursor.getLong(DataContactsQuery.DATA_ID);
15535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID);
15541f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            } else {
15551f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                // No contact found, return a null URI
15561f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                return -1;
15571f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
15581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } finally {
155931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            if (cursor != null) {
156031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                cursor.close();
156131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
15621f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
15631f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
15641f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        values.put(Presence.DATA_ID, dataId);
15655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        values.put(Presence.RAW_CONTACT_ID, rawContactId);
15661f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
15671f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        // Insert the presence update
1568de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        long presenceId = mDb.replace(Tables.PRESENCE, null, values);
15691f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        return presenceId;
15701f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    }
15711f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
15724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
1573de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
1574508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        final int match = sUriMatcher.match(uri);
1575508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        switch (match) {
157635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
1577de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mOpenHelper.getSyncState().delete(mDb, selection, selectionArgs);
157835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1579d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
1580d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
15816bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
1582d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                // Remove references to the contact first
15836bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                ContentValues values = new ContentValues();
1584d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values.putNull(RawContacts.CONTACT_ID);
1585de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                mDb.update(Tables.RAW_CONTACTS, values,
1586d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        RawContacts.CONTACT_ID + "=" + contactId, null);
15876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
1588de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.delete(Tables.CONTACTS, BaseColumns._ID + "=" + contactId, null);
15896bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
15906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
15915ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
159233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                return deleteRawContact(uri);
1593508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
1594508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
159520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
159673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                return deleteData(selection, selectionArgs, shouldMarkRawContactAsDirty(uri));
159720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
159820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1599508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            case DATA_ID: {
1600508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey                long dataId = ContentUris.parseId(uri);
1601f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov                return deleteData(Data._ID + "=" + dataId, null, shouldMarkRawContactAsDirty(uri));
1602ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1603ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1604ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
160594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                return deleteGroup(uri);
1606508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
1607508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
16081f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            case PRESENCE: {
1609de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.delete(Tables.PRESENCE, null, null);
16101f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
16111f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
1612508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            default:
16133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                return mLegacyApiSupport.delete(uri, selection, selectionArgs);
1614508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        }
16154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
16164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
161794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    private int deleteGroup(Uri uri) {
161894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        final String flag = uri.getQueryParameter(Groups.DELETE_PERMANENTLY);
161994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        final boolean permanently = flag != null && "true".equals(flag.toLowerCase());
162073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        boolean markAsDirty = shouldMarkGroupAsDirty(uri);
162173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        return deleteGroup(ContentUris.parseId(uri), markAsDirty, permanently);
162294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
162394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
162473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private int deleteGroup(long groupId, boolean markAsDirty, boolean permanently) {
162594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        final long groupMembershipMimetypeId = mOpenHelper
162694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
1627de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mDb.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "="
162894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "="
162994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupId, null);
163094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
163194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        try {
163294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            if (permanently) {
1633de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null);
163494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            } else {
163594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.clear();
163694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.put(Groups.DELETED, 1);
163773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                if (markAsDirty) {
163873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                    mValues.put(Groups.DIRTY, 1);
163973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                }
1640de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, null);
164194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            }
164294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        } finally {
164394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            mOpenHelper.updateAllVisible();
164494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
164594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
164694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
164733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    private int deleteRawContact(Uri uri) {
16487a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        final String flag = uri.getQueryParameter(RawContacts.DELETE_PERMANENTLY);
16497a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        final boolean permanently = flag != null && "true".equals(flag.toLowerCase());
16507a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        final long rawContactId = ContentUris.parseId(uri);
16517a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        return deleteRawContact(rawContactId, permanently);
165233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
165333b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
16545ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public int deleteRawContact(long rawContactId, boolean permanently) {
1655c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        // TODO delete aggregation exceptions
1656c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        mOpenHelper.removeContactIfSingleton(rawContactId);
165733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        if (permanently) {
1658de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            mDb.delete(Tables.PRESENCE, Presence.RAW_CONTACT_ID + "=" + rawContactId, null);
1659de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            return mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null);
166033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        } else {
166111944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov
166211944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov            // Clear out data used for aggregation - this deleted contact should not be aggregated
166311944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov            mDb.execSQL("DELETE FROM " + Tables.NAME_LOOKUP + " WHERE "
166411944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov                    + NameLookupColumns.RAW_CONTACT_ID + "=" + rawContactId);
166511944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov
166633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov            mValues.clear();
166794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            mValues.put(RawContacts.DELETED, 1);
1668c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
1669c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            mValues.putNull(RawContacts.CONTACT_ID);
167073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            mValues.put(RawContacts.DIRTY, 1);
16715ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return updateRawContact(rawContactId, mValues, null, null);
167233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        }
167333b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
167433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
1675f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana    private static Account readAccountFromQueryParams(Uri uri) {
16766cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String name = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
16776cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String type = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
1678f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(type)) {
1679f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana            return null;
1680f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        }
1681f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        return new Account(name, type);
1682f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana    }
1683f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana
16844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
1685de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int updateInTransaction(Uri uri, ContentValues values, String selection,
1686de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            String[] selectionArgs) {
168735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        int count = 0;
168800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
168900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        final int match = sUriMatcher.match(uri);
169000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        switch(match) {
169135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
1692de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mOpenHelper.getSyncState().update(mDb, values, selection, selectionArgs);
169335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1694d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            // TODO(emillar): We will want to disallow editing the contacts table at some point.
1695d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
1696de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = mDb.update(Tables.CONTACTS, values, selection, selectionArgs);
169700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
169800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
169900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
1700d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
1701de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateContactData(ContentUris.parseId(uri), values);
1702c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                break;
1703c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar            }
1704c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
170520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
170673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                count = updateData(uri, values, selection, selectionArgs,
170773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        shouldMarkRawContactAsDirty(uri));
170820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                break;
170920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
1710c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
171120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA_ID: {
171273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                count = updateData(uri, values, selection, selectionArgs,
171373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        shouldMarkRawContactAsDirty(uri));
171400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
171500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
17167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
17175ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
171873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
171973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                // TODO: security checks
1720de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = mDb.update(Tables.RAW_CONTACTS, values, selection, selectionArgs);
17217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
17227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
17237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
17245ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
172533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
172633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                count = updateRawContact(rawContactId, values, selection, selectionArgs);
17277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
17287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
17297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
1730ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
1731de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateGroups(values, selection, selectionArgs,
173273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        shouldMarkGroupAsDirty(uri));
1733ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
1734ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1735ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1736ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
1737ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
173873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                String selectionWithId = (Groups._ID + "=" + groupId + " ")
173973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        + (selection == null ? "" : " AND " + selection);
1740de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateGroups(values, selectionWithId, selectionArgs,
174173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        shouldMarkGroupAsDirty(uri));
1742ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
1743ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1744ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1745127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
1746de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateAggregationException(mDb, values);
1747b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
1748b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
1749b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
17507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            default:
1751f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.update(uri, values, selection, selectionArgs);
175200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        }
175300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
175400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        return count;
17554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
17564f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1757de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    private int updateGroups(ContentValues values, String selectionWithId,
175873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            String[] selectionArgs, boolean markAsDirty) {
175973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
176073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        ContentValues updatedValues;
176173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (markAsDirty) {
176273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = mValues;
176373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.clear();
176473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.putAll(values);
176573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.put(Groups.DIRTY, 1);
176673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        } else {
176773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = values;
176873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
176973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1770de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        int count = mDb.update(Tables.GROUPS, values, selectionWithId, selectionArgs);
177194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
177294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        // If changing visibility, then update contacts
177394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        if (values.containsKey(Groups.GROUP_VISIBLE)) {
177494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            mOpenHelper.updateAllVisible();
177594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
177694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        return count;
177794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
177894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
17795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private int updateRawContact(long rawContactId, ContentValues values, String selection,
178033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov            String[] selectionArgs) {
178173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
178273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        // TODO: security checks
17835ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        String selectionWithId = (RawContacts._ID + " = " + rawContactId + " ")
178433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                + (selection == null ? "" : " AND " + selection);
1785de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return mDb.update(Tables.RAW_CONTACTS, values, selectionWithId, selectionArgs);
178633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
178733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
1788321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    private int updateData(Uri uri, ContentValues values, String selection,
178973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            String[] selectionArgs, boolean markRawContactAsDirty) {
179020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int count = 0;
1791de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov
1792de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
1793de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // so we don't need to worry about updating data we don't have permission to read.
1794de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        Cursor c = query(uri, DataIdQuery.COLUMNS, selection, selectionArgs, null);
179520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        try {
1796de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            while(c.moveToNext()) {
1797de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                final long dataId = c.getLong(DataIdQuery._ID);
1798de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                final long rawContactId = c.getLong(DataIdQuery.RAW_CONTACT_ID);
1799de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                final String mimetype = c.getString(DataIdQuery.MIMETYPE);
1800de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count += updateData(dataId, rawContactId, mimetype, values,
1801de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                        markRawContactAsDirty);
180220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
180320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
1804de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            c.close();
180520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
180620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
180720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        return count;
180820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
180920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
181073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private int updateData(long dataId, long rawContactId, String mimeType, ContentValues values,
181173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            boolean markRawContactAsDirty) {
181220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.clear();
181320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.putAll(values);
181420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data._ID);
18155ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mValues.remove(Data.RAW_CONTACT_ID);
181620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
181720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
181820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        String packageName = values.getAsString(Data.RES_PACKAGE);
181920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        if (packageName != null) {
182020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.remove(Data.RES_PACKAGE);
182120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
182220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
182320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
182470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsSuperPrimary = mValues.containsKey(Data.IS_SUPER_PRIMARY);
182570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsPrimary = mValues.containsKey(Data.IS_PRIMARY);
182620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
182720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // Remove primary or super primary values being set to 0. This is disallowed by the
182820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // content provider.
182970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsSuperPrimary && mValues.getAsInteger(Data.IS_SUPER_PRIMARY) == 0) {
183020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsSuperPrimary = false;
183170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_SUPER_PRIMARY);
183220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
183370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsPrimary && mValues.getAsInteger(Data.IS_PRIMARY) == 0) {
183420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsPrimary = false;
183570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_PRIMARY);
183620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
183720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
183820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        if (containsIsSuperPrimary) {
183920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            setIsSuperPrimary(dataId);
184020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            setIsPrimary(dataId);
184120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
184220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            // Now that we've taken care of setting these, remove them from "values".
184370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_SUPER_PRIMARY);
184420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (containsIsPrimary) {
184570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                mValues.remove(Data.IS_PRIMARY);
184620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
184720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } else if (containsIsPrimary) {
184820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            setIsPrimary(dataId);
184920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
185020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            // Now that we've taken care of setting this, remove it from "values".
185170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_PRIMARY);
185220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
185320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
185473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        // TODO create GroupMembershipRowHandler and move this code there
1855de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        resolveGroupSourceIdInValues(rawContactId, mimeType, mDb, mValues, false /* isInsert */);
1856321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana
185770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (mValues.size() > 0) {
1858de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            mDb.update(Tables.DATA, mValues, Data._ID + " = " + dataId, null);
185973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            if (markRawContactAsDirty) {
186073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                setRawContactDirty(rawContactId);
186173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            }
186273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
186373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            return 1;
186420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
186520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        return 0;
186620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
186720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1868321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    private void resolveGroupSourceIdInValues(long rawContactId, String mimeType, SQLiteDatabase db,
1869321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana            ContentValues values, boolean isInsert) {
1870321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
1871321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana            boolean containsGroupSourceId = values.containsKey(GroupMembership.GROUP_SOURCE_ID);
1872321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana            boolean containsGroupId = values.containsKey(GroupMembership.GROUP_ROW_ID);
1873321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana            if (containsGroupSourceId && containsGroupId) {
1874321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                throw new IllegalArgumentException(
1875321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                        "you are not allowed to set both the GroupMembership.GROUP_SOURCE_ID "
1876321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                                + "and GroupMembership.GROUP_ROW_ID");
1877321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana            }
1878321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana
1879321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana            if (!containsGroupSourceId && !containsGroupId) {
1880321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                if (isInsert) {
1881321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                    throw new IllegalArgumentException(
1882321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                            "you must set exactly one of GroupMembership.GROUP_SOURCE_ID "
1883321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                                    + "and GroupMembership.GROUP_ROW_ID");
1884321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                } else {
1885321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                    return;
1886321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                }
1887321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana            }
1888321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana
1889321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana            if (containsGroupSourceId) {
1890321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                final String sourceId = values.getAsString(GroupMembership.GROUP_SOURCE_ID);
1891321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                final long groupId = getOrMakeGroup(db, rawContactId, sourceId);
1892321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                values.remove(GroupMembership.GROUP_SOURCE_ID);
1893321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana                values.put(GroupMembership.GROUP_ROW_ID, groupId);
1894321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana            }
1895321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        }
1896321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    }
1897321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana
1898de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    private int updateContactData(long contactId, ContentValues values) {
1899d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
1900d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // First update all constituent contacts
1901f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        ContentValues optionValues = new ContentValues(5);
19026cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyStringValue(optionValues, RawContacts.CUSTOM_RINGTONE,
1903d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.CUSTOM_RINGTONE);
19046cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.SEND_TO_VOICEMAIL,
1905d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.SEND_TO_VOICEMAIL);
19066cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.LAST_TIME_CONTACTED,
1907d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.LAST_TIME_CONTACTED);
19086cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.TIMES_CONTACTED,
1909d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.TIMES_CONTACTED);
19106cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.STARRED,
1911d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.STARRED);
1912d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
1913d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // Nothing to update - just return
1914d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        if (optionValues.size() == 0) {
1915d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov            return 0;
1916d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        }
1917d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
1918de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mDb.update(Tables.RAW_CONTACTS, optionValues,
1919d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                RawContacts.CONTACT_ID + "=" + contactId, null);
1920de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return mDb.update(Tables.CONTACTS, values, Contacts._ID + "=" + contactId, null);
1921f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
1922d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
1923d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    public void updateContactTime(long contactId, long lastTimeContacted) {
1924f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        mLastTimeContactedUpdate.bindLong(1, lastTimeContacted);
1925d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        mLastTimeContactedUpdate.bindLong(2, contactId);
1926f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        mLastTimeContactedUpdate.execute();
1927d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov    }
1928d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
19295ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static class RawContactPair {
19305ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        final long rawContactId1;
19315ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        final long rawContactId2;
1932127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
1933127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        /**
19345ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov         * Constructor that ensures that this.rawContactId1 &lt; this.rawContactId2
1935127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov         */
19365ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public RawContactPair(long rawContactId1, long rawContactId2) {
19375ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            if (rawContactId1 < rawContactId2) {
19385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId1 = rawContactId1;
19395ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId2 = rawContactId2;
1940127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            } else {
19415ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId2 = rawContactId1;
19425ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId1 = rawContactId2;
1943127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            }
1944127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        }
1945127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov    }
194680c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
1947127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov    private int updateAggregationException(SQLiteDatabase db, ContentValues values) {
1948127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        int exceptionType = values.getAsInteger(AggregationExceptions.TYPE);
1949d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        long contactId = values.getAsInteger(AggregationExceptions.CONTACT_ID);
19505ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        long rawContactId = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID);
195180c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
19523cfe8d532d509fbbe605454e3a32b2361b7e1501Dmitri Plotnikov        // First, we build a list of rawContactID-rawContactID pairs for the given contact.
19535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        ArrayList<RawContactPair> pairs = new ArrayList<RawContactPair>();
1954d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        Cursor c = db.query(ContactsQuery.TABLE, ContactsQuery.PROJECTION, RawContacts.CONTACT_ID
1955d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + "=" + contactId, null, null, null, null);
1956127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        try {
1957127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            while (c.moveToNext()) {
19585ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long aggregatedContactId = c.getLong(ContactsQuery.RAW_CONTACT_ID);
19595ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                if (aggregatedContactId != rawContactId) {
19605ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    pairs.add(new RawContactPair(aggregatedContactId, rawContactId));
1961e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov                }
1962b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
1963b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        } finally {
1964b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            c.close();
1965b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        }
1966127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
1967127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // Now we iterate through all contact pairs to see if we need to insert/delete/update
1968127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // the corresponding exception
1969127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        ContentValues exceptionValues = new ContentValues(3);
1970127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        exceptionValues.put(AggregationExceptions.TYPE, exceptionType);
19715ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        for (RawContactPair pair : pairs) {
1972127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            final String whereClause =
19735ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    AggregationExceptionColumns.RAW_CONTACT_ID1 + "=" + pair.rawContactId1 + " AND "
19745ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + AggregationExceptionColumns.RAW_CONTACT_ID2 + "=" + pair.rawContactId2;
1975127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) {
1976127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                db.delete(Tables.AGGREGATION_EXCEPTIONS, whereClause, null);
1977127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            } else {
19785ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                exceptionValues.put(AggregationExceptionColumns.RAW_CONTACT_ID1, pair.rawContactId1);
19795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                exceptionValues.put(AggregationExceptionColumns.RAW_CONTACT_ID2, pair.rawContactId2);
1980127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID,
1981127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                        exceptionValues);
1982127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            }
1983127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        }
1984127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
1985de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        int aggregationMode = mContactAggregator.markContactForAggregation(mDb, rawContactId);
19866cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        if (aggregationMode != RawContacts.AGGREGATION_MODE_DISABLED) {
19875ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            mContactAggregator.aggregateContact(db, rawContactId);
1988f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC
1989f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                    || exceptionType == AggregationExceptions.TYPE_KEEP_OUT) {
1990d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                mContactAggregator.updateAggregateData(contactId);
1991f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            }
19927a39bf269294a8130ddd463460b9b36cf4ff74a8Dmitri Plotnikov        }
1993127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
1994127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // The return value is fake - we just confirm that we made a change, not count actual
1995127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // rows changed.
1996127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        return 1;
1997b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    }
1998b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
1999619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
2000619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Test if a {@link String} value appears in the given list.
2001619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
2002619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private boolean isContained(String[] array, String value) {
2003bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        if (array != null) {
2004bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar            for (String test : array) {
2005bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar                if (value.equals(test)) {
2006bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar                    return true;
2007bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar                }
2008619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            }
2009619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
2010619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        return false;
2011619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
2012619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2013619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
2014619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Test if a {@link String} value appears in the given list, and add to the
2015619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * array if the value doesn't already appear.
2016619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
2017619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private String[] assertContained(String[] array, String value) {
201800ec508630251d6c6e3746469c9428f5a8cd5996Jeff Sharkey        if (array != null && !isContained(array, value)) {
2019619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            String[] newArray = new String[array.length + 1];
2020619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            System.arraycopy(array, 0, newArray, 0, array.length);
2021619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            newArray[array.length] = value;
2022619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            array = newArray;
2023619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
2024619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        return array;
2025619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
2026619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
20274f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
20284f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
20294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            String sortOrder) {
20304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
203135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2032d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
20331f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String groupBy = null;
2034c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limit = getLimit(uri);
2035c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2036619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // TODO: Consider writing a test case for RestrictionExceptions when you
2037619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // write a new query() block to make sure it protects restricted data.
2038a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
20394f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
204035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
204135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                return mOpenHelper.getSyncState().query(db, projection, selection,  selectionArgs,
204235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                        sortOrder);
204335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2044d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
20454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
2046d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsProjectionMap);
2047619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                break;
2048619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            }
2049619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2050d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
20514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
20524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getContactView());
2053d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsProjectionMap);
20544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Contacts._ID + "=" + contactId);
20556bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
20566bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
20576bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
2058d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY: {
2059619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                // TODO: join into social status tables
20604a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getContactSummaryView());
2061d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
20624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                groupBy = Contacts._ID;
20631f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                break;
20641f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
20651f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2066d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY_ID: {
2067619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                // TODO: join into social status tables
20684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
20694a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getContactSummaryView());
2070d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
20714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                groupBy = Contacts._ID;
20724a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Contacts._ID + "=" + contactId);
20731f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                break;
20741f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
20751f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2076d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY_FILTER: {
20774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getContactSummaryView());
2078d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
20794a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                groupBy = Contacts._ID;
20804a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
2081ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
20824a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
20834a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
20844a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    sb.append("raw_contact_id IN ");
20854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    appendRawContactsByFilterAsNestedQuery(sb, filterParam, null);
20864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(sb.toString());
2087ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
2088ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2089ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2090ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
2091d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY_STREQUENT_FILTER:
2092d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY_STREQUENT: {
20934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                String filterSql = null;
2094d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                if (match == CONTACTS_SUMMARY_STREQUENT_FILTER
2095d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        && uri.getPathSegments().size() > 3) {
20964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
20974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
20984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    sb.append("raw_contact_id IN ");
20994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    appendRawContactsByFilterAsNestedQuery(sb, filterParam, null);
21004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    filterSql = sb.toString();
21014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
21024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
21034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                // Build the first query for starred
21044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getContactSummaryView());
21054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
21064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
21074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
2108d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2109d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                final String starredQuery = qb.buildQuery(projection, Contacts.STARRED + "=1",
21104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
2111d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2112d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Build the second query for frequent
2113d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                qb = new SQLiteQueryBuilder();
21144a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getContactSummaryView());
2115d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
21164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
21174a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
2118d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2119d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String frequentQuery = qb.buildQuery(projection,
2120d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        Contacts.TIMES_CONTACTED + " > 0 AND (" + Contacts.STARRED
2121d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        + " = 0 OR " + Contacts.STARRED + " IS NULL)",
21224a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
2123d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2124d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Put them together
2125d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery},
2126d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        STREQUENT_ORDER_BY, STREQUENT_LIMIT);
21274a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                Cursor c = db.rawQuery(query, null);
21284a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (c != null) {
2129d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                    c.setNotificationUri(getContext().getContentResolver(),
2130d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                            ContactsContract.AUTHORITY_URI);
2131d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2132d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                return c;
2133d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar            }
2134d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2135d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY_GROUP: {
21364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getContactSummaryView());
2137d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
2138b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                if (uri.getPathSegments().size() > 2) {
21394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(sContactsInGroupSelect);
21404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
2141b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                }
21424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                groupBy = Contacts._ID;
2143b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                break;
2144b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            }
2145b67163a1088f09c59f324350662eb18772fac6b6Evan Millar
2146d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_DATA: {
21474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
21484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
21494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
21504a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
21514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
21524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=" + contactId);
21536bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
21546bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
215500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
21564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case PHONES: {
21574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
21584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
21594a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
21602815f58f72f109790585931f601a63ddc02536a5Evan Millar                break;
21612815f58f72f109790585931f601a63ddc02536a5Evan Millar            }
21622815f58f72f109790585931f601a63ddc02536a5Evan Millar
2163ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case PHONES_FILTER: {
21644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
21654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
2166ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                qb.appendWhere(Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
2167ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
21684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
21694a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
21704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    sb.append(Data.RAW_CONTACT_ID + " IN ");
21714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    appendRawContactsByFilterAsNestedQuery(sb, filterParam, null);
21724a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(" AND " + sb);
2173ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
2174ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2175ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2176ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
21774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case EMAILS: {
21784a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
21794a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
21804a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
21814a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                break;
21824a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            }
21834a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
21844a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case EMAILS_FILTER: {
21854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
21864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
21874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
21884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (uri.getPathSegments().size() > 2) {
21894a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(" AND " + CommonDataKinds.Email.DATA + "=");
21904a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhereEscapeString(uri.getLastPathSegment());
21914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
2192ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2193ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2194ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
2195ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case POSTALS: {
21964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
21974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
21984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.MIMETYPE + " = '" + StructuredPostal.CONTENT_ITEM_TYPE + "'");
2199ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2200ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2201ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
22025ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
22034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getRawContactView());
2204d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sRawContactsProjectionMap);
22054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
22064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
22074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
22085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
22095ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
22104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getRawContactView());
2211d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sRawContactsProjectionMap);
22124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(RawContacts._ID + "=" + rawContactId);
22134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
22144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
22154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
22165ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
22175ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = Long.parseLong(uri.getPathSegments().get(1));
22184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
22194a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
22204a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data.RAW_CONTACT_ID + "=" + rawContactId);
2221e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
2222e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
2223e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
2224e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            case DATA: {
22254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
22264a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
22274a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
2228e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
2229e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
2230e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
22314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            case DATA_ID: {
22324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setTables(mOpenHelper.getDataView());
22334a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.setProjectionMap(sDataProjectionMap);
22344a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                qb.appendWhere(Data._ID + "=" + ContentUris.parseId(uri));
22354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
22364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
22374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
2238a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case PHONE_LOOKUP: {
22394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
22404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                // TODO: optimize this query returning fewer fields and using an int mimetype
2241619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                // TODO: filter query based on callingUid
2242a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                if (TextUtils.isEmpty(sortOrder)) {
2243a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // Default the sort order to something reasonable so we get consistent
2244a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // results when callers don't request an ordering
22455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    sortOrder = Data.RAW_CONTACT_ID;
2246a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                }
2247a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2248a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                final String number = uri.getLastPathSegment();
224911944a13b31aa7c98f1079697f24b3a1999ca571Dmitri Plotnikov                OpenHelper.buildPhoneLookupQuery(qb, number, true /* join mimetype */);
22500c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar                qb.setProjectionMap(sDataRawContactsProjectionMap);
2251a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
2252a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
2253a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2254ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
2255ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2256ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
2257ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2258ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2259ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2260ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
2261ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
2262ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2263ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
2264ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.appendWhere(GroupsColumns.CONCRETE_ID + "=" + groupId);
2265ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2266ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2267ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2268ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_SUMMARY: {
226999a9b5ec879f6cd6876f7f6b680b82d8304e6b92Dmitri Plotnikov                qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2270ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsSummaryProjectionMap);
2271ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                groupBy = GroupsColumns.CONCRETE_ID;
2272ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2273ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2274ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2275b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
22765ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.setTables(Tables.AGGREGATION_EXCEPTIONS_JOIN_RAW_CONTACTS);
2277b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                qb.setProjectionMap(sAggregationExceptionsProjectionMap);
2278b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
2279b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
2280b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
228131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_SUGGESTIONS: {
2282d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
228331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                final int maxSuggestions;
2284d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                if (limit != null) {
2285d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                    maxSuggestions = Integer.parseInt(limit);
228631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                } else {
228731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                    maxSuggestions = DEFAULT_MAX_SUGGESTIONS;
228831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                }
228931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
2290d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                return mContactAggregator.queryAggregationSuggestions(contactId, projection,
2291d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        sContactsProjectionMap, maxSuggestions);
229231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
229331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
22945ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case PRESENCE: {
2295373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setTables(Tables.PRESENCE);
2296373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setProjectionMap(sPresenceProjectionMap);
22975ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
22985ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
22995ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
23005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case PRESENCE_ID: {
2301373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setTables(Tables.PRESENCE);
2302373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setProjectionMap(sPresenceProjectionMap);
2303373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.appendWhere(Presence._ID + "=" + ContentUris.parseId(uri));
23045ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
23055ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
23065ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
2307c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS: {
2308a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov                return mGlobalSearchSupport.handleSearchSuggestionsQuery(db, uri, limit);
2309c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
2310c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2311c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT: {
2312c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                // TODO
2313c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                break;
2314c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
2315c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
23164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            default:
2317f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.query(uri, projection, selection, selectionArgs,
2318c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                        sortOrder, limit);
23194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
23204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
23214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        // Perform the query and set the notification uri
23221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        final Cursor c = qb.query(db, projection, selection, selectionArgs,
2323bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar                groupBy, null, sortOrder, limit);
23244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        if (c != null) {
23254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI);
23264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
23274f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        return c;
23284f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
23294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
23304a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) {
23314a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
23324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
23334a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (!TextUtils.isEmpty(accountName)) {
23344a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
23354a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountName) + " AND "
23364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + RawContacts.ACCOUNT_TYPE + "="
23374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountType));
23384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        } else {
23394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere("1");
23404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        }
23414a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    }
23424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
23437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
2344c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * Gets the value of the "limit" URI query parameter.
2345c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *
2346c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * @return A string containing a non-negative integer, or <code>null</code> if
2347c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *         the parameter is not set, or is set to an invalid value.
2348c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     */
2349c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private String getLimit(Uri url) {
2350c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limitParam = url.getQueryParameter("limit");
2351c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limitParam == null) {
2352c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
2353c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
2354c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        // make sure that the limit is a non-negative integer
2355c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        try {
2356c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            int l = Integer.parseInt(limitParam);
2357c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            if (l < 0) {
2358c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                Log.w(TAG, "Invalid limit parameter: " + limitParam);
2359c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return null;
2360c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
2361c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return String.valueOf(l);
2362c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        } catch (NumberFormatException ex) {
2363c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            Log.w(TAG, "Invalid limit parameter: " + limitParam);
2364c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
2365c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
2366c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
2367c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
236800ec508630251d6c6e3746469c9428f5a8cd5996Jeff Sharkey    String getContactsRestrictions() {
23694a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (mOpenHelper.hasRestrictedAccess()) {
237070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
237170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        } else {
23726cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            return RawContacts.IS_RESTRICTED + "=0";
237370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
237470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    }
237570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
237670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    public String getContactsRestrictionExceptionAsNestedQuery(String contactIdColumn) {
23774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        if (mOpenHelper.hasRestrictedAccess()) {
237870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
237967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        } else {
23805ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return "(SELECT " + RawContacts.IS_RESTRICTED + " FROM " + Tables.RAW_CONTACTS
23815ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + " WHERE " + RawContactsColumns.CONCRETE_ID + "=" + contactIdColumn + ")=0";
2382619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
2383619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
2384619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2385619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
23867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     * An implementation of EntityIterator that joins the contacts and data tables
23877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     * and consumes all the data rows for a contact in order to build the Entity for a contact.
23887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
23897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    private static class ContactsEntityIterator implements EntityIterator {
23907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private final Cursor mEntityCursor;
23917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private volatile boolean mIsClosed;
23927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
23937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private static final String[] DATA_KEYS = new String[]{
23947a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA1,
23957a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA2,
23967a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA3,
23977a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA4,
23987a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA5,
23997a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA6,
24007a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA7,
24017a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA8,
24027a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA9,
24037a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA10,
24047a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA11,
24057a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA12,
24067a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA13,
24077a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA14,
24087a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA15,
24097a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC1,
24107a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC2,
24117a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC3,
24127a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC4};
24137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
24147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private static final String[] PROJECTION = new String[]{
24156cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.ACCOUNT_NAME,
24166cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
24176cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.SOURCE_ID,
24186cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.VERSION,
24196cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.DIRTY,
24207a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data._ID,
24217a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.RES_PACKAGE,
24227a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.MIMETYPE,
24237a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA1,
24247a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA2,
24257a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA3,
24267a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA4,
24277a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA5,
24287a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA6,
24297a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA7,
24307a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA8,
24317a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA9,
24327a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA10,
24337a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA11,
24347a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA12,
24357a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA13,
24367a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA14,
24377a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA15,
24387a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC1,
24397a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC2,
24407a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC3,
24417a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.SYNC4,
24427a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.RAW_CONTACT_ID,
24437a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.IS_PRIMARY,
24447a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Data.DATA_VERSION,
24457a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                GroupMembership.GROUP_SOURCE_ID,
24467a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC1,
24477a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC2,
24487a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                RawContacts.SYNC3,
244994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                RawContacts.SYNC4,
245094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                RawContacts.DELETED};
2451035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana
2452035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_ACCOUNT_NAME = 0;
2453035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_ACCOUNT_TYPE = 1;
2454035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_SOURCE_ID = 2;
2455035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_VERSION = 3;
2456035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_DIRTY = 4;
2457035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_DATA_ID = 5;
245867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_RES_PACKAGE = 6;
245967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_MIMETYPE = 7;
246067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_DATA1 = 8;
24617a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_RAW_CONTACT_ID = 27;
24627a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_IS_PRIMARY = 28;
24637a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_DATA_VERSION = 29;
24647a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_GROUP_SOURCE_ID = 30;
24657a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC1 = 31;
24667a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC2 = 32;
24677a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC3 = 33;
24687a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC4 = 34;
246994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        private static final int COLUMN_DELETED = 35;
24707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
24717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public ContactsEntityIterator(ContactsProvider2 provider, String contactsIdString, Uri uri,
24727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                String selection, String[] selectionArgs, String sortOrder) {
24737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mIsClosed = false;
24747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
24757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final String updatedSortOrder = (sortOrder == null)
24767a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                    ? Data.RAW_CONTACT_ID
24777a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                    : (Data.RAW_CONTACT_ID + "," + sortOrder);
24787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
24797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase();
24807e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
2481226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setTables(Tables.CONTACT_ENTITIES);
24827e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (contactsIdString != null) {
24835ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.appendWhere(Data.RAW_CONTACT_ID + "=" + contactsIdString);
24847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
24856cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
24866cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
2487035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            if (!TextUtils.isEmpty(accountName)) {
24886cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
2489035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                        + DatabaseUtils.sqlEscapeString(accountName) + " AND "
24906cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                        + RawContacts.ACCOUNT_TYPE + "="
2491035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                        + DatabaseUtils.sqlEscapeString(accountType));
2492035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            }
24937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs,
24947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    null, null, updatedSortOrder);
24957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor.moveToFirst();
24967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
24977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
24987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public void close() {
24997e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
25007e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("closing when already closed");
25017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
25027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mIsClosed = true;
25037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor.close();
25047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
25057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public boolean hasNext() throws RemoteException {
25077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
25087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("calling hasNext() when the iterator is closed");
25097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
25107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return !mEntityCursor.isAfterLast();
25127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
25137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public Entity next() throws RemoteException {
25157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
25167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("calling next() when the iterator is closed");
25177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
25187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (!hasNext()) {
25197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("you may only call next() if hasNext() is true");
25207e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
25217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteCursor c = (SQLiteCursor) mEntityCursor;
25237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25247a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            final long rawContactId = c.getLong(COLUMN_RAW_CONTACT_ID);
25257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            // we expect the cursor is already at the row we need to read from
25277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            ContentValues contactValues = new ContentValues();
25286cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME));
25296cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE));
25305ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            contactValues.put(RawContacts._ID, rawContactId);
25316cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.DIRTY, c.getLong(COLUMN_DIRTY));
25326cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.VERSION, c.getLong(COLUMN_VERSION));
25336cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.SOURCE_ID, c.getString(COLUMN_SOURCE_ID));
25347a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC1, c.getString(COLUMN_SYNC1));
25357a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC2, c.getString(COLUMN_SYNC2));
25367a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC3, c.getString(COLUMN_SYNC3));
25377a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            contactValues.put(RawContacts.SYNC4, c.getString(COLUMN_SYNC4));
253894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            contactValues.put(RawContacts.DELETED, c.getLong(COLUMN_DELETED));
25397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            Entity contact = new Entity(contactValues);
25407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            // read data rows until the contact id changes
25427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            do {
25437a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                if (rawContactId != c.getLong(COLUMN_RAW_CONTACT_ID)) {
25447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    break;
25457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
25467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                // add the data to to the contact
25477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                ContentValues dataValues = new ContentValues();
25487a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data._ID, c.getString(COLUMN_DATA_ID));
25497a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.RES_PACKAGE, c.getString(COLUMN_RES_PACKAGE));
25507a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.MIMETYPE, c.getString(COLUMN_MIMETYPE));
25517a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.IS_PRIMARY, c.getString(COLUMN_IS_PRIMARY));
25527a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION));
25539261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (!c.isNull(COLUMN_GROUP_SOURCE_ID)) {
25549261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    dataValues.put(GroupMembership.GROUP_SOURCE_ID,
25559261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            c.getString(COLUMN_GROUP_SOURCE_ID));
25569261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
25577a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                dataValues.put(Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION));
25587a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                for (int i = 0; i < DATA_KEYS.length; i++) {
25597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    final int columnIndex = i + COLUMN_DATA1;
25607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    String key = DATA_KEYS[i];
25617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    if (c.isNull(columnIndex)) {
25627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        // don't put anything
25637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isLong(columnIndex)) {
25647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getLong(columnIndex));
25657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isFloat(columnIndex)) {
25667e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getFloat(columnIndex));
25677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isString(columnIndex)) {
25687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getString(columnIndex));
25697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isBlob(columnIndex)) {
25707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getBlob(columnIndex));
25717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    }
25727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
25737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                contact.addSubValue(Data.CONTENT_URI, dataValues);
25747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            } while (mEntityCursor.moveToNext());
25757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25767e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return contact;
25777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
25787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
25797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
2580226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    /**
2581226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     * An implementation of EntityIterator that joins the contacts and data tables
2582226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     * and consumes all the data rows for a contact in order to build the Entity for a contact.
2583226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     */
2584226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    private static class GroupsEntityIterator implements EntityIterator {
2585226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private final Cursor mEntityCursor;
2586226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private volatile boolean mIsClosed;
2587226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2588226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final String[] PROJECTION = new String[]{
2589226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups._ID,
2590226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.ACCOUNT_NAME,
2591226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.ACCOUNT_TYPE,
2592226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.SOURCE_ID,
2593226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.DIRTY,
2594226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.VERSION,
2595226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.RES_PACKAGE,
2596226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.TITLE,
2597226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.TITLE_RES,
25987a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.GROUP_VISIBLE,
25997a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC1,
26007a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC2,
26017a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC3,
26027a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYNC4,
26037a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                Groups.SYSTEM_ID,
260494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                Groups.NOTES,
260594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                Groups.DELETED};
2606226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2607226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ID = 0;
2608226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ACCOUNT_NAME = 1;
2609226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ACCOUNT_TYPE = 2;
2610226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_SOURCE_ID = 3;
2611226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_DIRTY = 4;
2612226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_VERSION = 5;
2613226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_RES_PACKAGE = 6;
2614226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_TITLE = 7;
2615226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_TITLE_RES = 8;
2616226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_GROUP_VISIBLE = 9;
26177a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC1 = 10;
26187a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC2 = 11;
26197a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC3 = 12;
26207a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYNC4 = 13;
26217a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_SYSTEM_ID = 14;
26227a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana        private static final int COLUMN_NOTES = 15;
262394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        private static final int COLUMN_DELETED = 16;
2624226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2625226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public GroupsEntityIterator(ContactsProvider2 provider, String groupIdString, Uri uri,
2626226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                String selection, String[] selectionArgs, String sortOrder) {
2627226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mIsClosed = false;
2628226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2629226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String updatedSortOrder = (sortOrder == null)
2630226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    ? Groups._ID
2631226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    : (Groups._ID + "," + sortOrder);
2632226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2633226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase();
2634226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
2635226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2636226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setProjectionMap(sGroupsProjectionMap);
2637226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (groupIdString != null) {
2638226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                qb.appendWhere(Groups._ID + "=" + groupIdString);
2639226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2640226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String accountName = uri.getQueryParameter(Groups.ACCOUNT_NAME);
2641226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String accountType = uri.getQueryParameter(Groups.ACCOUNT_TYPE);
2642226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (!TextUtils.isEmpty(accountName)) {
2643226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                qb.appendWhere(Groups.ACCOUNT_NAME + "="
2644226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + DatabaseUtils.sqlEscapeString(accountName) + " AND "
2645226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + Groups.ACCOUNT_TYPE + "="
2646226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + DatabaseUtils.sqlEscapeString(accountType));
2647226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2648226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs,
2649226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    null, null, updatedSortOrder);
2650226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.moveToFirst();
2651226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
2652226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2653226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public void close() {
2654226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
2655226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("closing when already closed");
2656226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2657226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mIsClosed = true;
2658226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.close();
2659226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
2660226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2661226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public boolean hasNext() throws RemoteException {
2662226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
2663226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("calling hasNext() when the iterator is closed");
2664226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2665226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2666226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            return !mEntityCursor.isAfterLast();
2667226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
2668226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2669226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public Entity next() throws RemoteException {
2670226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
2671226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("calling next() when the iterator is closed");
2672226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2673226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (!hasNext()) {
2674226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("you may only call next() if hasNext() is true");
2675226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2676226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2677226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteCursor c = (SQLiteCursor) mEntityCursor;
2678226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2679226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final long groupId = c.getLong(COLUMN_ID);
2680226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2681226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            // we expect the cursor is already at the row we need to read from
2682226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            ContentValues groupValues = new ContentValues();
2683226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME));
2684226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE));
2685226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups._ID, groupId);
2686226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.DIRTY, c.getLong(COLUMN_DIRTY));
2687226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.VERSION, c.getLong(COLUMN_VERSION));
2688226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.SOURCE_ID, c.getString(COLUMN_SOURCE_ID));
2689226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.RES_PACKAGE, c.getString(COLUMN_RES_PACKAGE));
2690226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.TITLE, c.getString(COLUMN_TITLE));
2691226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.TITLE_RES, c.getString(COLUMN_TITLE_RES));
2692226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.GROUP_VISIBLE, c.getLong(COLUMN_GROUP_VISIBLE));
26937a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC1, c.getString(COLUMN_SYNC1));
26947a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC2, c.getString(COLUMN_SYNC2));
26957a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC3, c.getString(COLUMN_SYNC3));
26967a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYNC4, c.getString(COLUMN_SYNC4));
26977a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.SYSTEM_ID, c.getString(COLUMN_SYSTEM_ID));
269894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            groupValues.put(Groups.DELETED, c.getLong(COLUMN_DELETED));
26997a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana            groupValues.put(Groups.NOTES, c.getString(COLUMN_NOTES));
2700226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            Entity group = new Entity(groupValues);
2701226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2702226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.moveToNext();
2703226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2704226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            return group;
2705226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
2706226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    }
2707226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2708a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    @Override
27097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
27107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            String sortOrder) {
27117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        final int match = sUriMatcher.match(uri);
27127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        switch (match) {
27135ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS:
27145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID:
27157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                String contactsIdString = null;
27165ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                if (match == RAW_CONTACTS_ID) {
27177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    contactsIdString = uri.getPathSegments().get(1);
27187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
27197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
27207e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                return new ContactsEntityIterator(this, contactsIdString,
27217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        uri, selection, selectionArgs, sortOrder);
2722226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            case GROUPS:
2723226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            case GROUPS_ID:
2724226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                String idString = null;
2725226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                if (match == GROUPS_ID) {
2726226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    idString = uri.getPathSegments().get(1);
2727226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                }
2728226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2729226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                return new GroupsEntityIterator(this, idString,
2730226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        uri, selection, selectionArgs, sortOrder);
27317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            default:
27327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new UnsupportedOperationException("Unknown uri: " + uri);
27337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
27347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
27357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
27364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
27374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public String getType(Uri uri) {
2738a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
27394f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
2740d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: return Contacts.CONTENT_TYPE;
2741d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: return Contacts.CONTENT_ITEM_TYPE;
27425ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: return RawContacts.CONTENT_TYPE;
27435ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: return RawContacts.CONTENT_ITEM_TYPE;
2744508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            case DATA_ID:
27456bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
2746508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey                long dataId = ContentUris.parseId(uri);
2747b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                return mOpenHelper.getDataMimeType(dataId);
274831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_EXCEPTIONS: return AggregationExceptions.CONTENT_TYPE;
274931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_EXCEPTION_ID: return AggregationExceptions.CONTENT_ITEM_TYPE;
2750d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case AGGREGATION_SUGGESTIONS: return Contacts.CONTENT_TYPE;
2751c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS:
2752c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SUGGEST_MIME_TYPE;
2753c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT:
2754c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SHORTCUT_MIME_TYPE;
27554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
2756a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        throw new UnsupportedOperationException("Unknown uri: " + uri);
27574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
27587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
27595ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private void setDisplayName(long rawContactId, String displayName) {
27603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (displayName != null) {
27613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mContactDisplayNameUpdate.bindString(1, displayName);
27623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        } else {
27633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mContactDisplayNameUpdate.bindNull(1);
27643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
27655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mContactDisplayNameUpdate.bindLong(2, rawContactId);
27663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mContactDisplayNameUpdate.execute();
27673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
27683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
276973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /**
277073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Checks the {@link Data#MARK_AS_DIRTY} query parameter.
277173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     *
277273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Returns true if the parameter is missing or is either "true" or "1".
277373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     */
277473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private boolean shouldMarkRawContactAsDirty(Uri uri) {
277573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (mImportMode) {
277673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            return false;
277773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
277873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
277973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        String param = uri.getQueryParameter(Data.MARK_AS_DIRTY);
278073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        return param == null || (!param.equalsIgnoreCase("false") && !param.equals("0"));
278173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    }
278273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
278373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /**
278473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Sets the {@link RawContacts#DIRTY} for the specified raw contact.
278573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     */
278673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private void setRawContactDirty(long rawContactId) {
278773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate.bindLong(1, rawContactId);
278873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        mRawContactDirtyUpdate.execute();
278973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    }
279073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
279173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    /**
279273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Checks the {@link Groups#MARK_AS_DIRTY} query parameter.
279373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     *
279473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     * Returns true if the parameter is missing or is either "true" or "1".
279573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov     */
279673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    private boolean shouldMarkGroupAsDirty(Uri uri) {
279773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        if (mImportMode) {
279873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            return false;
279973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
280073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
280173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        String param = uri.getQueryParameter(Groups.MARK_AS_DIRTY);
280273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        return param == null || (!param.equalsIgnoreCase("false") && !param.equals("0"));
280373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov    }
280473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
2805c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
2806c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to primary, and resets all data records of
2807c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * the same mimetype and under the same contact to not be primary.
2808c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
2809c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
2810c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
2811c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private void setIsPrimary(long dataId) {
2812c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.bindLong(1, dataId);
2813c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.bindLong(2, dataId);
2814c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.bindLong(3, dataId);
2815c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.execute();
2816c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
2817c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
2818c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
2819c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to "super primary", and resets all data
2820c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * records of the same mimetype and under the same aggregate to not be "super primary".
2821c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
2822c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
2823c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
2824c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private void setIsSuperPrimary(long dataId) {
2825c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.bindLong(1, dataId);
2826c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.bindLong(2, dataId);
2827c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.bindLong(3, dataId);
2828c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.execute();
2829c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
2830ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
28315ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public String getRawContactsByFilterAsNestedQuery(String filterParam) {
2832c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        StringBuilder sb = new StringBuilder();
2833c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        appendRawContactsByFilterAsNestedQuery(sb, filterParam, null);
2834c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        return sb.toString();
2835c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
2836c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2837a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    public void appendRawContactsByFilterAsNestedQuery(StringBuilder sb, String filterParam,
2838c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            String limit) {
2839c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append("(SELECT DISTINCT raw_contact_id FROM name_lookup WHERE normalized_name GLOB '");
2840c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append(NameNormalizer.normalize(filterParam));
2841c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append("*'");
2842c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limit != null) {
2843c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            sb.append(" LIMIT ").append(limit);
2844c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
2845c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append(")");
2846ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    }
2847ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
28484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /**
28494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     * Inserts an argument at the beginning of the selection arg list.
28504a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     */
28514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private String[] insertSelectionArg(String[] selectionArgs, String arg) {
2852b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        if (selectionArgs == null) {
2853b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return new String[] {arg};
2854b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        } else {
2855b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            int newLength = selectionArgs.length + 1;
2856b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            String[] newSelectionArgs = new String[newLength];
28574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            newSelectionArgs[0] = arg;
28584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length);
2859b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return newSelectionArgs;
2860b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        }
2861b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    }
2862caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
2863caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    protected Account getDefaultAccount() {
2864caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        AccountManager accountManager = AccountManager.get(getContext());
2865caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        try {
2866caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            Account[] accounts = accountManager.blockingGetAccountsWithTypeAndFeatures(
2867caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov                    DEFAULT_ACCOUNT_TYPE, new String[] {FEATURE_APPS_FOR_DOMAIN});
2868caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            if (accounts != null && accounts.length > 0) {
2869caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov                return accounts[0];
2870caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            }
2871caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        } catch (Throwable e) {
2872caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            throw new RuntimeException("Cannot determine the default account "
2873caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov                    + "for contacts compatibility", e);
2874caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        }
2875caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        throw new RuntimeException("Cannot determine the default account "
2876caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov                + "for contacts compatibility");
2877caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    }
28784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton}
2879