ContactsProvider2.java revision a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0
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;
2667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport com.android.providers.contacts.OpenHelper.PackagesColumns;
27d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.PhoneColumns;
2828f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.PhoneLookupColumns;
29d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.RawContactsColumns;
3028f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.Tables;
31e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikovimport com.google.android.collect.Lists;
32e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
33b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account;
34c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager;
354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.content.ContentProvider;
3667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentProviderOperation;
3767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentProviderResult;
3835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris;
3967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues;
4067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context;
4135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.Entity;
4267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.EntityIterator;
437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport android.content.OperationApplicationException;
4467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher;
4567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.pm.PackageManager;
464f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor;
47ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils;
48b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.database.sqlite.SQLiteCursor;
494f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase;
504f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder;
51c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millarimport android.database.sqlite.SQLiteStatement;
524f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri;
53619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.os.Binder;
54b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException;
55508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns;
56de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract;
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;
73d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.AggregationSuggestions;
74a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils;
75a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils;
76c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log;
774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList;
79b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap;
804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/**
824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications
834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}.
844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */
85035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintanapublic class ContactsProvider2 extends ContentProvider {
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
95a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
97d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, "
98d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.TIMES_CONTACTED + " DESC, "
99d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.DISPLAY_NAME + " ASC";
100d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar    private static final String STREQUENT_LIMIT =
101d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE "
102d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.STARRED + "=1) + 25";
103d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov
104d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS = 1000;
105d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS_ID = 1001;
106d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS_DATA = 1002;
107d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS_SUMMARY = 1003;
1082815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final int CONTACTS_RAW_CONTACTS = 1004;
1092815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final int CONTACTS_SUMMARY_ID = 1005;
1102815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final int CONTACTS_SUMMARY_FILTER = 1006;
1112815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final int CONTACTS_SUMMARY_STREQUENT = 1007;
1122815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final int CONTACTS_SUMMARY_STREQUENT_FILTER = 1008;
1132815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final int CONTACTS_SUMMARY_GROUP = 1009;
1144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1155ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS = 2002;
1165ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_ID = 2003;
1175ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_DATA = 2004;
11828ab0f857caa92402878244d9c5ea2a59e070935Jeff Sharkey    private static final int CONTACTS_FILTER_EMAIL = 2005;
1194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1206bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA = 3000;
1216bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA_ID = 3001;
122ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int PHONES = 3002;
123ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int PHONES_FILTER = 3003;
124ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int POSTALS = 3004;
125a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1266bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int PHONE_LOOKUP = 4000;
1276bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
128b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTIONS = 6000;
129b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTION_ID = 6001;
130b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
1311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    private static final int PRESENCE = 7000;
1321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    private static final int PRESENCE_ID = 7001;
1331f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
13431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    private static final int AGGREGATION_SUGGESTIONS = 8000;
13531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
136ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS = 10000;
137ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_ID = 10001;
138ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_SUMMARY = 10003;
139ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
14035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana    private static final int SYNCSTATE = 11000;
14135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
142c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SUGGESTIONS = 12001;
143c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SHORTCUT = 12002;
144c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
14567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    private interface ContactsQuery {
1465ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final String TABLE = Tables.RAW_CONTACTS;
1479261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
14867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
1496cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
1506cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.ACCOUNT_NAME,
1516cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.ACCOUNT_TYPE,
152ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
153ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1545ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
15567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int ACCOUNT_NAME = 1;
15667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int ACCOUNT_TYPE = 2;
15767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    }
15867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
159d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private interface DataRawContactsQuery {
1605ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final String TABLE = Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS;
16167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
16267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
1636cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
1643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
165d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            RawContacts.CONTACT_ID,
1666cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContacts.IS_RESTRICTED,
1673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.MIMETYPE,
168ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
169ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1705ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
17167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA_ID = 1;
172d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int CONTACT_ID = 2;
17367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int IS_RESTRICTED = 3;
17467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int MIMETYPE = 4;
17567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    }
17667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
177d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private interface DataContactsQuery {
178d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS;
17967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
18067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
1816cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
1823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
183d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            ContactsColumns.CONCRETE_ID,
1843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.CONCRETE_ID,
1853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Phone.NUMBER,
1863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Email.DATA,
187d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            ContactsColumns.OPTIMAL_PRIMARY_PHONE_ID,
188d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            ContactsColumns.FALLBACK_PRIMARY_PHONE_ID,
189d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            ContactsColumns.OPTIMAL_PRIMARY_EMAIL_ID,
190d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            ContactsColumns.FALLBACK_PRIMARY_EMAIL_ID,
191ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
192ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
193d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
19467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA_ID = 1;
195d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int CONTACT_ID = 2;
19667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int MIMETYPE_ID = 3;
19767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int PHONE_NUMBER = 4;
19867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int EMAIL_DATA = 5;
19967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int OPTIMAL_PHONE_ID = 6;
20067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int FALLBACK_PHONE_ID = 7;
20167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int OPTIMAL_EMAIL_ID = 8;
20267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int FALLBACK_EMAIL_ID = 9;
20380c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
204ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
2051f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private interface DisplayNameQuery {
20767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
2083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final String[] COLUMNS = new String[] {
2103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
2113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
2123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA2,
2133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            StructuredName.DISPLAY_NAME,
2143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
2153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 0;
2173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 1;
2183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA2 = 2;
2193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DISPLAY_NAME = 3;
2203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
2213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private interface DataQuery {
22367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
2243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final String[] COLUMNS = new String[] {
2263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
2273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
2285ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Data.RAW_CONTACT_ID,
2293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
2303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA1,
2313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA2,
2323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA3,
2333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA4,
2343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA5,
2353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA6,
2363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA7,
2373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA8,
2383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA9,
2393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.DATA10,
24067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            Data.DATA11,
24167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            Data.DATA12,
24267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            Data.DATA13,
24367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            Data.DATA14,
24467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            Data.DATA15,
2453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
2463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int ID = 0;
2483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 1;
2495ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 2;
2503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 3;
2513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA1 = 4;
2523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA2 = 5;
2533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA3 = 6;
2543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA4 = 7;
2553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA5 = 8;
2563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA6 = 9;
2573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA7 = 10;
2583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA8 = 11;
2593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA9 = 12;
2603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int DATA10 = 13;
26167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA11 = 14;
26267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA12 = 15;
26367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA13 = 16;
26467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA14 = 17;
26567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA15 = 18;
2663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
2673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
26820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private interface DataIdQuery {
26920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        String[] COLUMNS = { Data._ID };
27020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
27120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int _ID = 0;
27220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
27320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    // Higher number represents higher priority in choosing what data to use for the display name
2753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_EMAIL = 1;
2763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_PHONE = 2;
2773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_ORGANIZATION = 3;
2783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DISPLAY_NAME_PRIORITY_STRUCTURED_NAME = 4;
2793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final HashMap<String, Integer> sDisplayNamePriorities;
2813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    static {
2823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities = new HashMap<String, Integer>();
2833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(StructuredName.CONTENT_ITEM_TYPE,
2843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_STRUCTURED_NAME);
2853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(Organization.CONTENT_ITEM_TYPE,
2863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_ORGANIZATION);
2873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(Phone.CONTENT_ITEM_TYPE,
2883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_PHONE);
2893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        sDisplayNamePriorities.put(Email.CONTENT_ITEM_TYPE,
2903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                DISPLAY_NAME_PRIORITY_EMAIL);
2913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
29231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
2936bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    /** Contains just the contacts columns */
2944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    private static final HashMap<String, String> sContactsProjectionMap;
295d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Contains the contact columns along with primary phone */
296d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final HashMap<String, String> sContactsSummaryProjectionMap;
297d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Contains the data, contacts, and contact columns, for joined tables. */
2980c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar    private static final HashMap<String, String> sDataRawContactsContactProjectionMap;
299d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Contains the data, contacts, group sourceid and contact columns, for joined tables. */
3000c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar    private static final HashMap<String, String> sDataRawContactsGroupsContactProjectionMap;
3012815f58f72f109790585931f601a63ddc02536a5Evan Millar    /** Contains the contacts, and raw contact columns, for joined tables. */
3022815f58f72f109790585931f601a63ddc02536a5Evan Millar    private static final HashMap<String, String> sRawContactsContactsProjectionMap;
303d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Contains just the contacts columns */
304d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final HashMap<String, String> sRawContactsProjectionMap;
305a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /** Contains just the data columns */
3069261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    private static final HashMap<String, String> sDataGroupsProjectionMap;
3079261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /** Contains the data and contacts columns, for joined tables */
3080c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar    private static final HashMap<String, String> sDataRawContactsGroupsProjectionMap;
309a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /** Contains the data and contacts columns, for joined tables */
3100c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar    private static final HashMap<String, String> sDataRawContactsProjectionMap;
311ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains the just the {@link Groups} columns */
312ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsProjectionMap;
313ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains {@link Groups} columns along with summary details */
314ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final HashMap<String, String> sGroupsSummaryProjectionMap;
315373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    /** Contains the agg_exceptions columns */
316b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final HashMap<String, String> sAggregationExceptionsProjectionMap;
317373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    /** Contains Presence columns */
318373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    private static final HashMap<String, String> sPresenceProjectionMap;
3197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
320c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Sql select statement that returns the contact id associated with a data record. */
321d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String sNestedRawContactIdSelect;
322c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Sql select statement that returns the mimetype id associated with a data record. */
323c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private static final String sNestedMimetypeSelect;
324d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Sql select statement that returns the contact id associated with a contact record. */
325d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String sNestedContactIdSelect;
326d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Sql select statement that returns a list of contact ids associated with an contact record. */
327c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private static final String sNestedContactIdListSelect;
328c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Sql where statement used to match all the data records that need to be updated when a new
329c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * "primary" is selected.*/
330c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private static final String sSetPrimaryWhere;
331c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Sql where statement used to match all the data records that need to be updated when a new
332c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * "super primary" is selected.*/
333c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private static final String sSetSuperPrimaryWhere;
334b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    /** Sql where statement for filtering on groups. */
335d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String sContactsInGroupSelect;
336c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /** Precompiled sql statement for setting a data record to the primary. */
337c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetPrimaryStatement;
3383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for setting a data record to the super primary. */
339c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private SQLiteStatement mSetSuperPrimaryStatement;
340d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    /** Precompiled sql statement for incrementing times contacted for an contact */
341f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private SQLiteStatement mLastTimeContactedUpdate;
3423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Precompiled sql statement for updating a contact display name */
3433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private SQLiteStatement mContactDisplayNameUpdate;
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);
3512815f58f72f109790585931f601a63ddc02536a5Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/raw_contacts", CONTACTS_RAW_CONTACTS);
352d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary", CONTACTS_SUMMARY);
353d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary/#", CONTACTS_SUMMARY_ID);
354d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary/filter/*",
355d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                CONTACTS_SUMMARY_FILTER);
356d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary/strequent/",
357d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                CONTACTS_SUMMARY_STREQUENT);
358d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary/strequent/filter/*",
359d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                CONTACTS_SUMMARY_STREQUENT_FILTER);
360d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts_summary/group/*",
361d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                CONTACTS_SUMMARY_GROUP);
362d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions",
36331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                AGGREGATION_SUGGESTIONS);
3645ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
3655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID);
3665ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA);
3675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/filter_email/*",
368b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                CONTACTS_FILTER_EMAIL);
369b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
3704f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);
3714f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID);
372ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES);
373ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER);
374ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS);
3751f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
376ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS);
377ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID);
378ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY);
379ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
38035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE);
38135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
382a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP);
383b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions",
384b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTIONS);
385b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*",
386b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTION_ID);
3874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
388bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "presence", PRESENCE);
389bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "presence/#", PRESENCE_ID);
3901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
391c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
392c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
393c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
394c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
395c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/#",
396c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SHORTCUT);
397c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
398fec4e13316f2731d84394e5fa2f93af3febdc20cEvan Millar        HashMap<String, String> columns;
3994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
400d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        // Contacts projection map
4016bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov        columns = new HashMap<String, String>();
402d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts._ID, "contacts._id AS _id");
403d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.DISPLAY_NAME, ContactsColumns.CONCRETE_DISPLAY_NAME + " AS "
404d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Contacts.DISPLAY_NAME);
405d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.LAST_TIME_CONTACTED, ContactsColumns.CONCRETE_LAST_TIME_CONTACTED
406d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " AS " + Contacts.LAST_TIME_CONTACTED);
407d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.TIMES_CONTACTED, ContactsColumns.CONCRETE_TIMES_CONTACTED + " AS "
408d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Contacts.TIMES_CONTACTED);
409d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.STARRED, ContactsColumns.CONCRETE_STARRED + " AS "
410d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Contacts.STARRED);
411d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.IN_VISIBLE_GROUP, Contacts.IN_VISIBLE_GROUP);
412d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
413d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.PRIMARY_PHONE_ID, Contacts.PRIMARY_PHONE_ID);
414d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.PRIMARY_EMAIL_ID, Contacts.PRIMARY_EMAIL_ID);
415d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.CUSTOM_RINGTONE, ContactsColumns.CONCRETE_CUSTOM_RINGTONE + " AS "
416d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Contacts.CUSTOM_RINGTONE);
417d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.SEND_TO_VOICEMAIL, ContactsColumns.CONCRETE_SEND_TO_VOICEMAIL
418d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " AS " + Contacts.SEND_TO_VOICEMAIL);
419d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(ContactsColumns.FALLBACK_PRIMARY_PHONE_ID,
420d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                ContactsColumns.FALLBACK_PRIMARY_PHONE_ID);
421d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(ContactsColumns.FALLBACK_PRIMARY_EMAIL_ID,
422d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                ContactsColumns.FALLBACK_PRIMARY_EMAIL_ID);
423d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        sContactsProjectionMap = columns;
4246bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
4251f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        columns = new HashMap<String, String>();
426d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.putAll(sContactsProjectionMap);
427c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov
428d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        // Contacts primaries projection map. The overall presence status is
429c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov        // the most-present value, as indicated by the largest value.
430d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.PRESENCE_STATUS, "MAX(" + Presence.PRESENCE_STATUS + ")");
431d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.PRIMARY_PHONE_TYPE, CommonDataKinds.Phone.TYPE);
432d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.PRIMARY_PHONE_LABEL, CommonDataKinds.Phone.LABEL);
433d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Contacts.PRIMARY_PHONE_NUMBER, CommonDataKinds.Phone.NUMBER);
434d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        sContactsSummaryProjectionMap = columns;
43500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
4366cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        // RawContacts projection map
4374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        columns = new HashMap<String, String>();
4385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        columns.put(RawContacts._ID, Tables.RAW_CONTACTS + "." + RawContacts._ID + " AS _id");
439d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
4406cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        columns.put(RawContacts.ACCOUNT_NAME,
4415ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_ACCOUNT_NAME
4425ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.ACCOUNT_NAME);
4436cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        columns.put(RawContacts.ACCOUNT_TYPE,
4445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_ACCOUNT_TYPE
4455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.ACCOUNT_TYPE);
4466cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        columns.put(RawContacts.SOURCE_ID,
4475ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_SOURCE_ID
4485ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.SOURCE_ID);
4496cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        columns.put(RawContacts.VERSION,
4505ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_VERSION
4515ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.VERSION);
4526cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        columns.put(RawContacts.DIRTY,
4535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_DIRTY
4545ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.DIRTY);
45533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        columns.put(RawContacts.DELETED,
4565ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                OpenHelper.RawContactsColumns.CONCRETE_DELETED
4575ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                        + " AS " + RawContacts.DELETED);
458d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        sRawContactsProjectionMap = columns;
4594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
4602815f58f72f109790585931f601a63ddc02536a5Evan Millar        columns = new HashMap<String, String>();
4612815f58f72f109790585931f601a63ddc02536a5Evan Millar        columns.putAll(sContactsProjectionMap);
4622815f58f72f109790585931f601a63ddc02536a5Evan Millar        columns.putAll(sRawContactsProjectionMap);
4632815f58f72f109790585931f601a63ddc02536a5Evan Millar        sRawContactsContactsProjectionMap = columns;
4642815f58f72f109790585931f601a63ddc02536a5Evan Millar
4654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        // Data projection map
4664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        columns = new HashMap<String, String>();
4675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        columns.put(Data._ID, Tables.DATA + "." + Data._ID + " AS _id");
4685ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        columns.put(Data.RAW_CONTACT_ID, Data.RAW_CONTACT_ID);
46967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.RES_PACKAGE, PackagesColumns.PACKAGE + " AS " + Data.RES_PACKAGE);
470508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        columns.put(Data.MIMETYPE, Data.MIMETYPE);
471c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        columns.put(Data.IS_PRIMARY, Data.IS_PRIMARY);
472c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        columns.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY);
473f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        columns.put(Data.DATA_VERSION, Data.DATA_VERSION);
4747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA1, "data.data1 as data1");
4757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA2, "data.data2 as data2");
4767e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA3, "data.data3 as data3");
4777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA4, "data.data4 as data4");
4787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA5, "data.data5 as data5");
4797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA6, "data.data6 as data6");
4807e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA7, "data.data7 as data7");
4817e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA8, "data.data8 as data8");
4827e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA9, "data.data9 as data9");
4837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        columns.put(Data.DATA10, "data.data10 as data10");
48467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.DATA11, "data.data11 as data11");
48567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.DATA12, "data.data12 as data12");
48667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.DATA13, "data.data13 as data13");
48767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.DATA14, "data.data14 as data14");
48867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Data.DATA15, "data.data15 as data15");
48967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(GroupMembership.GROUP_SOURCE_ID, GroupsColumns.CONCRETE_SOURCE_ID + " AS "
49067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + GroupMembership.GROUP_SOURCE_ID);
49120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
49220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // TODO: remove this projection
493d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar        // Mappings used for backwards compatibility.
494d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar        columns.put("number", Phone.NUMBER);
4959261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        sDataGroupsProjectionMap = columns;
496a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
4979261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // Data, groups and contacts projection map for joins. _id comes from the data table
498a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        columns = new HashMap<String, String>();
499d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.putAll(sRawContactsProjectionMap);
5009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.putAll(sDataGroupsProjectionMap); // _id will be replaced with the one from data
501d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Data.RAW_CONTACT_ID, DataColumns.CONCRETE_RAW_CONTACT_ID);
5020c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar        sDataRawContactsGroupsProjectionMap = columns;
5039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
5049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // Data and contacts projection map for joins. _id comes from the data table
5059261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns = new HashMap<String, String>();
5060c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar        columns.putAll(sDataRawContactsGroupsProjectionMap);
5079261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.remove(GroupMembership.GROUP_SOURCE_ID);
5080c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar        sDataRawContactsProjectionMap = columns;
5097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
510de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar        // Data and contacts projection map for joins. _id comes from the data table
511de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar        columns = new HashMap<String, String>();
512d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.putAll(sContactsProjectionMap);
513d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.putAll(sRawContactsProjectionMap); //
5149261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.putAll(sDataGroupsProjectionMap); // _id will be replaced with the one from data
515d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Data.RAW_CONTACT_ID, DataColumns.CONCRETE_RAW_CONTACT_ID);
5160c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar        sDataRawContactsGroupsContactProjectionMap = columns;
5179261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
5189261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // Data and contacts projection map for joins. _id comes from the data table
5199261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns = new HashMap<String, String>();
5200c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar        columns.putAll(sDataRawContactsGroupsContactProjectionMap);
5219261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.remove(GroupMembership.GROUP_SOURCE_ID);
5220c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar        sDataRawContactsContactProjectionMap = columns;
523c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
524ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Groups projection map
525ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
526ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups._ID, "groups._id AS _id");
527035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_NAME, Groups.ACCOUNT_NAME);
528035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        columns.put(Groups.ACCOUNT_TYPE, Groups.ACCOUNT_TYPE);
5299261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.SOURCE_ID, Groups.SOURCE_ID);
5309261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.DIRTY, Groups.DIRTY);
5319261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        columns.put(Groups.VERSION, Groups.VERSION);
53267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Groups.RES_PACKAGE, PackagesColumns.PACKAGE + " AS " + Groups.RES_PACKAGE);
533ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.TITLE, Groups.TITLE);
53467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        columns.put(Groups.TITLE_RES, Groups.TITLE_RES);
535ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.GROUP_VISIBLE, Groups.GROUP_VISIBLE);
536ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsProjectionMap = columns;
537ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
5386cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        // RawContacts and groups projection map
539ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns = new HashMap<String, String>();
540ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.putAll(sGroupsProjectionMap);
541ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
542d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(Groups.SUMMARY_COUNT, "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID
543d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
544ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
545ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + ") AS " + Groups.SUMMARY_COUNT);
546ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
547ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        columns.put(Groups.SUMMARY_WITH_PHONES, "(SELECT COUNT(DISTINCT "
548d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + ContactsColumns.CONCRETE_ID + ") FROM "
549d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS + " WHERE "
550ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP
551ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + " AND " + Clauses.HAS_PRIMARY_PHONE + ") AS " + Groups.SUMMARY_WITH_PHONES);
552ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
553ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        sGroupsSummaryProjectionMap = columns;
554ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
555b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        // Aggregate exception projection map
556b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns = new HashMap<String, String>();
557b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id AS _id");
558b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        columns.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE);
559d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        columns.put(AggregationExceptions.CONTACT_ID,
560d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                "raw_contacts1." + RawContacts.CONTACT_ID
561d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " AS " + AggregationExceptions.CONTACT_ID);
5625ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        columns.put(AggregationExceptions.RAW_CONTACT_ID, AggregationExceptionColumns.RAW_CONTACT_ID2);
563b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        sAggregationExceptionsProjectionMap = columns;
564b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
565373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov
566373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns = new HashMap<String, String>();
567373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence._ID, Presence._ID);
568373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.RAW_CONTACT_ID, Presence.RAW_CONTACT_ID);
569373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.DATA_ID, Presence.DATA_ID);
570373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.IM_ACCOUNT, Presence.IM_ACCOUNT);
571373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.IM_HANDLE, Presence.IM_HANDLE);
572373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.IM_PROTOCOL, Presence.IM_PROTOCOL);
573373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.PRESENCE_STATUS, Presence.PRESENCE_STATUS);
574373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        columns.put(Presence.PRESENCE_CUSTOM_STATUS, Presence.PRESENCE_CUSTOM_STATUS);
575373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov        sPresenceProjectionMap = columns;
576373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov
577d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        sNestedRawContactIdSelect = "SELECT " + Data.RAW_CONTACT_ID + " FROM " + Tables.DATA + " WHERE "
578c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + Data._ID + "=?";
579c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        sNestedMimetypeSelect = "SELECT " + DataColumns.MIMETYPE_ID + " FROM " + Tables.DATA
580c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + " WHERE " + Data._ID + "=?";
581d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        sNestedContactIdSelect = "SELECT " + RawContacts.CONTACT_ID + " FROM " + Tables.RAW_CONTACTS
582d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " WHERE " + RawContacts._ID + "=(" + sNestedRawContactIdSelect + ")";
5835ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        sNestedContactIdListSelect = "SELECT " + RawContacts._ID + " FROM " + Tables.RAW_CONTACTS
584d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + " WHERE " + RawContacts.CONTACT_ID + "=(" + sNestedContactIdSelect + ")";
585d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        sSetPrimaryWhere = Data.RAW_CONTACT_ID + "=(" + sNestedRawContactIdSelect + ") AND "
586c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + DataColumns.MIMETYPE_ID + "=(" + sNestedMimetypeSelect + ")";
5875ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        sSetSuperPrimaryWhere = Data.RAW_CONTACT_ID + " IN (" + sNestedContactIdListSelect + ") AND "
588c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + DataColumns.MIMETYPE_ID + "=(" + sNestedMimetypeSelect + ")";
589d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        sContactsInGroupSelect = ContactsColumns.CONCRETE_ID + " IN (SELECT "
590d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + RawContacts.CONTACT_ID + " FROM " + Tables.RAW_CONTACTS + " WHERE ("
5916cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                + RawContactsColumns.CONCRETE_ID + " IN (SELECT " + Tables.DATA + "."
5925ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                + Data.RAW_CONTACT_ID + " FROM " + Tables.DATA_JOIN_MIMETYPES + " WHERE ("
593b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE + "' AND "
594b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                + GroupMembership.GROUP_ROW_ID + "=(SELECT " + Tables.GROUPS + "."
595b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                + Groups._ID + " FROM " + Tables.GROUPS + " WHERE " + Groups.TITLE + "=?)))))";
5964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
5974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
5983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /**
5993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     * Handles inserts and update for a specific Data type.
6003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     */
6013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private abstract class DataRowHandler {
6023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected final String mMimetype;
6043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public DataRowHandler(String mimetype) {
6063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mMimetype = mimetype;
6073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
6103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Inserts a row into the {@link Data} table.
6113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
6125ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
613e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            final long dataId = db.insert(Tables.DATA, null, values);
614e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
615e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            Integer primary = values.getAsInteger(Data.IS_PRIMARY);
616e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (primary != null && primary != 0) {
617e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                setIsPrimary(dataId);
618e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
619e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
6205ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            fixContactDisplayName(db, rawContactId);
621e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return dataId;
6223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
6253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Validates data and updates a {@link Data} row using the cursor, which contains
6263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * the current data.
6273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
6283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor cursor) {
6293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            throw new UnsupportedOperationException();
6303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public int delete(SQLiteDatabase db, Cursor c) {
6333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            long dataId = c.getLong(DataQuery.ID);
6345ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long rawContactId = c.getLong(DataQuery.RAW_CONTACT_ID);
6353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            boolean primary = c.getInt(DataQuery.IS_PRIMARY) != 0;
6363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            int count = db.delete(Tables.DATA, Data._ID + "=" + dataId, null);
6373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (count != 0 && primary) {
6385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                fixPrimary(db, rawContactId);
6395ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                fixContactDisplayName(db, rawContactId);
6403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
6413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return count;
6423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        private void fixPrimary(SQLiteDatabase db, long rawContactId) {
6455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long newPrimaryId = findNewPrimaryDataId(db, rawContactId);
6463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (newPrimaryId != -1) {
6473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                ContactsProvider2.this.setIsPrimary(newPrimaryId);
6483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
6493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6515ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected long findNewPrimaryDataId(SQLiteDatabase db, long rawContactId) {
652e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            long primaryId = -1;
653e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            int primaryType = -1;
6545ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Cursor c = queryData(db, rawContactId);
6553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
656e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                while (c.moveToNext()) {
657e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    long dataId = c.getLong(DataQuery.ID);
658e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    int type = c.getInt(DataQuery.DATA2);
659e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) {
660e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryId = dataId;
661e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryType = type;
662e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    }
6633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
6643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
6653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
6663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
667e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return primaryId;
668e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
669e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
670e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        /**
671e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * Returns the rank of a specific record type to be used in determining the primary
672e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * row. Lower number represents higher priority.
673e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         */
674e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
675e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return 0;
6763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6785ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected Cursor queryData(SQLiteDatabase db, long rawContactId) {
6793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            // TODO Lookup integer mimetype IDs' instead of joining for speed
6805ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return db.query(DataQuery.TABLE, DataQuery.COLUMNS, Data.RAW_CONTACT_ID + "="
6815ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + rawContactId + " AND " + MimetypesColumns.MIMETYPE + "='" + mMimetype + "'",
6823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    null, null, null, null);
6833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
6843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
6855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        protected void fixContactDisplayName(SQLiteDatabase db, long rawContactId) {
686e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (!sDisplayNamePriorities.containsKey(mMimetype)) {
687e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                return;
688e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
689e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
6903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String bestDisplayName = null;
69167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            Cursor c = db.query(DisplayNameQuery.TABLE, DisplayNameQuery.COLUMNS,
6925ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    Data.RAW_CONTACT_ID + "=" + rawContactId, null, null, null, null);
6933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
6943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                int maxPriority = -1;
6953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                while (c.moveToNext()) {
6963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    String mimeType = c.getString(DisplayNameQuery.MIMETYPE);
6973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    boolean primary;
6983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    String name;
6993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
7013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        name = c.getString(DisplayNameQuery.DISPLAY_NAME);
7023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        primary = true;
7033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    } else {
7043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        name = c.getString(DisplayNameQuery.DATA2);
7053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        primary = (c.getInt(DisplayNameQuery.IS_PRIMARY) != 0);
7063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    }
7073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    if (primary && name != null) {
7093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        Integer priority = sDisplayNamePriorities.get(mimeType);
7103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        if (priority != null && priority > maxPriority) {
7113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                            maxPriority = priority;
7123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                            bestDisplayName = name;
7133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        }
7143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    }
7153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
7163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
7183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
7193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
7203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7215ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            ContactsProvider2.this.setDisplayName(rawContactId, bestDisplayName);
7223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
7243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CustomDataRowHandler extends DataRowHandler {
7263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CustomDataRowHandler(String mimetype) {
7283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
7293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
7313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class StructuredNameRowHandler extends DataRowHandler {
7333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final NameSplitter mNameSplitter;
7353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public StructuredNameRowHandler(NameSplitter nameSplitter) {
7373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(StructuredName.CONTENT_ITEM_TYPE);
7383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mNameSplitter = nameSplitter;
7393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
7425ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
7433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            fixStructuredNameComponents(values);
7445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return super.insert(db, rawContactId, values);
7453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
7483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor cursor) {
7493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            // TODO Parse the full name if it has changed and replace pre-existing piece parts.
7503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
7533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Parses the supplied display name, but only if the incoming values do not already contain
7543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * structured name parts.  Also, if the display name is not provided, generate one by
7553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * concatenating first name and last name
7563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         *
7573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * TODO see if the order of first and last names needs to be conditionally reversed for
7583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * some locales, e.g. China.
7593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
7603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private void fixStructuredNameComponents(ContentValues values) {
7613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String fullName = values.getAsString(StructuredName.DISPLAY_NAME);
7623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (!TextUtils.isEmpty(fullName)
7633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.PREFIX))
7643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.GIVEN_NAME))
7653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.MIDDLE_NAME))
7663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.FAMILY_NAME))
7673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    && TextUtils.isEmpty(values.getAsString(StructuredName.SUFFIX))) {
7683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                NameSplitter.Name name = new NameSplitter.Name();
7693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                mNameSplitter.split(name, fullName);
7703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.PREFIX, name.getPrefix());
7723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.GIVEN_NAME, name.getGivenNames());
7733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.MIDDLE_NAME, name.getMiddleName());
7743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.FAMILY_NAME, name.getFamilyName());
7753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                values.put(StructuredName.SUFFIX, name.getSuffix());
7763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
7773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (TextUtils.isEmpty(fullName)) {
7793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                String givenName = values.getAsString(StructuredName.GIVEN_NAME);
7803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                String familyName = values.getAsString(StructuredName.FAMILY_NAME);
7813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                if (TextUtils.isEmpty(givenName)) {
7823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = familyName;
7833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                } else if (TextUtils.isEmpty(familyName)) {
7843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = givenName;
7853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                } else {
7863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    fullName = givenName + " " + familyName;
7873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
7883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                if (!TextUtils.isEmpty(fullName)) {
7903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                    values.put(StructuredName.DISPLAY_NAME, fullName);
7913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
7923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
7933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
7943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
7953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CommonDataRowHandler extends DataRowHandler {
7973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
7983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mTypeColumn;
7993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mLabelColumn;
8003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CommonDataRowHandler(String mimetype, String typeColumn, String labelColumn) {
8023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
8033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mTypeColumn = typeColumn;
8043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mLabelColumn = labelColumn;
8053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
8085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
8093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            int type;
8103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            String label;
8113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (values.containsKey(mTypeColumn)) {
8123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                type = values.getAsInteger(mTypeColumn);
8133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } else {
8143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                type = BaseTypes.TYPE_CUSTOM;
8153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (values.containsKey(mLabelColumn)) {
8173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                label = values.getAsString(mLabelColumn);
8183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } else {
8193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                label = null;
8203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (type != BaseTypes.TYPE_CUSTOM && label != null) {
8233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                throw new RuntimeException(mLabelColumn + " value can only be specified with "
8243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        + mTypeColumn + "=" + BaseTypes.TYPE_CUSTOM + "(custom)");
8253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (type == BaseTypes.TYPE_CUSTOM && label == null) {
8283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                throw new RuntimeException(mLabelColumn + " value must be specified when "
8293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                        + mTypeColumn + "=" + BaseTypes.TYPE_CUSTOM + "(custom)");
8303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8325ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return super.insert(db, rawContactId, values);
8333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
8363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public void update(SQLiteDatabase db, ContentValues values, Cursor cursor) {
8373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            // TODO read the data and check the constraint
8383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
8403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class OrganizationDataRowHandler extends CommonDataRowHandler {
8423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public OrganizationDataRowHandler() {
8443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Organization.CONTENT_ITEM_TYPE, Organization.TYPE, Organization.LABEL);
8453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
8485ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
8495ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long id = super.insert(db, rawContactId, values);
8505ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            fixContactDisplayName(db, rawContactId);
8513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return id;
8523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
8553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
8563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
8573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_WORK: return 0;
8583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_CUSTOM: return 1;
8593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_OTHER: return 2;
8603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
8613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
8623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
8643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
865e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    public class EmailDataRowHandler extends CommonDataRowHandler {
866e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
867e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public EmailDataRowHandler() {
868e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            super(Email.CONTENT_ITEM_TYPE, Email.TYPE, Email.LABEL);
869e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
870e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
871e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
8725ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
8735ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long id = super.insert(db, rawContactId, values);
8745ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            fixContactDisplayName(db, rawContactId);
875e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return id;
876e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
877e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
878e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
879e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
880e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            switch (type) {
881e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_HOME: return 0;
882e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_WORK: return 1;
883e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_CUSTOM: return 2;
884e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_OTHER: return 3;
885e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                default: return 1000;
886e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
887e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
888e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    }
889e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
8903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class PhoneDataRowHandler extends CommonDataRowHandler {
8913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public PhoneDataRowHandler() {
8933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Phone.CONTENT_ITEM_TYPE, Phone.TYPE, Phone.LABEL);
8943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
8953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
8963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
8975ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
898e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            ContentValues phoneValues = new ContentValues();
899e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            String number = values.getAsString(Phone.NUMBER);
900e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            String normalizedNumber = null;
901e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (number != null) {
902e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                normalizedNumber = PhoneNumberUtils.getStrippedReversed(number);
903e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                values.put(PhoneColumns.NORMALIZED_NUMBER, normalizedNumber);
904e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
905e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
9065ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long id = super.insert(db, rawContactId, values);
9073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
908e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (number != null) {
9095ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.RAW_CONTACT_ID, rawContactId);
910e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.DATA_ID, id);
911e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, normalizedNumber);
912e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                db.insert(Tables.PHONE_LOOKUP, null, phoneValues);
913e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
9143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return id;
9163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
9193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
9203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
9213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_MOBILE: return 0;
9223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_WORK: return 1;
9233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_HOME: return 2;
9243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_PAGER: return 3;
9253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_CUSTOM: return 4;
9263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_OTHER: return 5;
9273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_WORK: return 6;
9283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_HOME: return 7;
9293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
9303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
9313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
9333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private HashMap<String, DataRowHandler> mDataRowHandlers;
93553056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov    private final ContactAggregationScheduler mAggregationScheduler;
9364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    private OpenHelper mOpenHelper;
93731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
938a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    private ContactAggregator mContactAggregator;
9394097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov    private NameSplitter mNameSplitter;
940f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private LegacyApiSupport mLegacyApiSupport;
941a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    private GlobalSearchSupport mGlobalSearchSupport;
942a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
94320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private ContentValues mValues = new ContentValues();
94420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
945a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    public ContactsProvider2() {
94653056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        this(new ContactAggregationScheduler());
947a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
948a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
949a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
950a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Constructor for testing.
951a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
95253056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov    /* package */ ContactsProvider2(ContactAggregationScheduler scheduler) {
95353056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        mAggregationScheduler = scheduler;
954a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
9554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
9564f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
9574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public boolean onCreate() {
958b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        final Context context = getContext();
95935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
96031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov        mOpenHelper = getOpenHelper(context);
961a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mGlobalSearchSupport = new GlobalSearchSupport(this);
962a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mLegacyApiSupport = new LegacyApiSupport(context, mOpenHelper, this, mGlobalSearchSupport);
96353056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov        mContactAggregator = new ContactAggregator(context, mOpenHelper, mAggregationScheduler);
964a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
965d51a83ac4f8032b62d9a23b90a8f43d6b7eb2dbbDmitri Plotnikov        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
966c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement = db.compileStatement(
967c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                "UPDATE " + Tables.DATA + " SET " + Data.IS_PRIMARY
968c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + "=(_id=?) WHERE " + sSetPrimaryWhere);
969c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement = db.compileStatement(
970c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                "UPDATE " + Tables.DATA + " SET " + Data.IS_SUPER_PRIMARY
971c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                + "=(_id=?) WHERE " + sSetSuperPrimaryWhere);
9725ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mLastTimeContactedUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
9736cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                + RawContacts.TIMES_CONTACTED + "=" + RawContacts.TIMES_CONTACTED + "+1,"
974d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + RawContacts.LAST_TIME_CONTACTED + "=? WHERE " + RawContacts.CONTACT_ID + "=?");
975a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
9765ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mContactDisplayNameUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET "
9776cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                + RawContactsColumns.DISPLAY_NAME + "=? WHERE " + RawContacts._ID + "=?");
9783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
97928f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar        mNameSplitter = new NameSplitter(
98028f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_prefixes),
98128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_last_name_prefixes),
98228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_suffixes),
98328f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                context.getString(com.android.internal.R.string.common_name_conjunctions));
9844097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
9853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers = new HashMap<String, DataRowHandler>();
9863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
987e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, new EmailDataRowHandler());
9883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE,
9893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new CommonDataRowHandler(Im.CONTENT_ITEM_TYPE, Im.TYPE, Im.LABEL));
99067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler(
99167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, StructuredPostal.LABEL));
9923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, new OrganizationDataRowHandler());
9933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, new PhoneDataRowHandler());
99467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler(
99567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE, Nickname.LABEL));
9963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE,
9973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                new StructuredNameRowHandler(mNameSplitter));
9983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        return (db != null);
10004f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
10014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
100231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    /* Visible for testing */
100331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    protected OpenHelper getOpenHelper(final Context context) {
100431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov        return OpenHelper.getInstance(context);
100531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    }
100631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
1007a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    @Override
1008a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    protected void finalize() throws Throwable {
1009a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        if (mContactAggregator != null) {
1010a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov            mContactAggregator.quit();
1011a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        }
1012a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1013a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        super.finalize();
1014a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1015a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1016a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
1017a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Wipes all data from the contacts database.
1018a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
1019a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /* package */ void wipeData() {
1020a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        mOpenHelper.wipeData();
1021a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
1022a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1023a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
1024a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Called when a change has been made.
1025a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
1026a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param uri the uri that the change was made to
1027a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
1028a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    private void onChange(Uri uri) {
1029a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null);
1030a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
1031a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
10324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
10334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public boolean isTemporary() {
10344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        return false;
10354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
10364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
10373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private DataRowHandler getDataRowHandler(final String mimeType) {
10383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        DataRowHandler handler = mDataRowHandlers.get(mimeType);
10393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (handler == null) {
10403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            handler = new CustomDataRowHandler(mimeType);
10413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mDataRowHandlers.put(mimeType, handler);
10423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
10433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        return handler;
10443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
10453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10464f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
10474f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public Uri insert(Uri uri, ContentValues values) {
1048a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
1049a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
105035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1051a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        switch (match) {
105235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
105335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                id = mOpenHelper.getSyncState().insert(mOpenHelper.getWritableDatabase(), values);
105435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                break;
105535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1056d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
1057d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                insertContact(values);
10586bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
10596bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
10606bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
10615ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
1062f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                final Account account = readAccountFromQueryParams(uri);
1063d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                id = insertRawContact(values, account);
1064a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1065a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1066a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
10675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
10685ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1));
1069035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                id = insertData(values);
1070a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1071a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1072a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1073a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case DATA: {
1074035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                id = insertData(values);
1075a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
1076a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
1077a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1078ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
1079ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                final Account account = readAccountFromQueryParams(uri);
1080ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                id = insertGroup(values, account);
1081ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
1082ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1083ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
10841f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            case PRESENCE: {
10851f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                id = insertPresence(values);
10861f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                break;
10871f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
10881f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
1089a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            default:
1090f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.insert(uri, values);
1091a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
1092a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
10937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        if (id < 0) {
10947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return null;
10957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
10967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
10977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        final Uri result = ContentUris.withAppendedId(uri, id);
1098a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        onChange(result);
1099a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        return result;
1100a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
1101a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1102a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
1103035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * If account is non-null then store it in the values. If the account is already
1104035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * specified in the values then it must be consistent with the account, if it is non-null.
1105035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @param values the ContentValues to read from and update
1106035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @param account the explicitly provided Account
1107035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana     * @return false if the accounts are inconsistent
11087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
1109035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana    private boolean resolveAccount(ContentValues values, Account account) {
1110035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        // If either is specified then both must be specified.
11116cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
11126cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
1113035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        if (!TextUtils.isEmpty(accountName) || !TextUtils.isEmpty(accountType)) {
1114035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            final Account valuesAccount = new Account(accountName, accountType);
1115035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            if (account != null && !valuesAccount.equals(account)) {
1116035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                return false;
1117035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            }
1118035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            account = valuesAccount;
1119035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
1120035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        if (account != null) {
11216cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            values.put(RawContacts.ACCOUNT_NAME, account.mName);
11226cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            values.put(RawContacts.ACCOUNT_TYPE, account.mType);
1123035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
1124035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        return true;
11257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
11267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
11277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
1128d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov     * Inserts an item in the contacts table
11296bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     *
11306bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @param values the values for the new row
11316bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @return the row ID of the newly created row
11326bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     */
1133d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertContact(ContentValues values) {
1134a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        throw new UnsupportedOperationException("Aggregates are created automatically");
11356bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    }
11366bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
11376bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    /**
1138a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the contacts table
1139a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
1140a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
1141f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana     * @param account the account this contact should be associated with. may be null.
1142a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
1143a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
1144d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertRawContact(ContentValues values, Account account) {
11456bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov        /*
11466bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         * The contact record is inserted in the contacts table, but it needs to
11476bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         * be processed by the aggregator before it will be returned by the
11486bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         * "aggregates" queries.
11496bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov         */
1150a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
11516bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
1152a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        ContentValues overriddenValues = new ContentValues(values);
1153d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        overriddenValues.putNull(RawContacts.CONTACT_ID);
1154f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        if (!resolveAccount(overriddenValues, account)) {
11557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return -1;
11567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
11577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
1158c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        return db.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, overriddenValues);
1159a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
1160a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
1161a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
1162a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the data table
1163a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
1164a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
1165a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
1166a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
1167035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana    private long insertData(ContentValues values) {
11686cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        int aggregationMode = RawContacts.AGGREGATION_MODE_DISABLED;
1169a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1170a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1171a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
1172a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        db.beginTransaction();
1173a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        try {
117420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.clear();
117520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.putAll(values);
117620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
11775ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID);
1178a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
117967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            // Replace package with internal mapping
118020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            final String packageName = mValues.getAsString(Data.RES_PACKAGE);
118167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            if (packageName != null) {
118220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
118367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            }
118420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.remove(Data.RES_PACKAGE);
118567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
1186619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            // Replace mimetype with internal mapping
118720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            final String mimeType = mValues.getAsString(Data.MIMETYPE);
118820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (TextUtils.isEmpty(mimeType)) {
118920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                throw new RuntimeException(Data.MIMETYPE + " is required");
119020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
119120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
119220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.put(DataColumns.MIMETYPE_ID, mOpenHelper.getMimeTypeId(mimeType));
119320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.remove(Data.MIMETYPE);
1194508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
11953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
119620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                boolean containsGroupSourceId = mValues.containsKey(GroupMembership.GROUP_SOURCE_ID);
119720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                boolean containsGroupId = mValues.containsKey(GroupMembership.GROUP_ROW_ID);
11989261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (containsGroupSourceId && containsGroupId) {
11999261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    throw new IllegalArgumentException(
12009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            "you are not allowed to set both the GroupMembership.GROUP_SOURCE_ID "
12019261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                                    + "and GroupMembership.GROUP_ROW_ID");
12029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
12039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
12049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (!containsGroupSourceId && !containsGroupId) {
12059261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    throw new IllegalArgumentException(
12069261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            "you must set exactly one of GroupMembership.GROUP_SOURCE_ID "
12079261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                                    + "and GroupMembership.GROUP_ROW_ID");
12089261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
12099261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
12109261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (containsGroupSourceId) {
121120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    final String sourceId = mValues.getAsString(GroupMembership.GROUP_SOURCE_ID);
12125ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    final long groupId = getOrMakeGroup(db, rawContactId, sourceId);
121320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    mValues.remove(GroupMembership.GROUP_SOURCE_ID);
121420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    mValues.put(GroupMembership.GROUP_ROW_ID, groupId);
12159261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
12164097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov            }
12174097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
12185ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            id = getDataRowHandler(mimeType).insert(db, rawContactId, mValues);
1219a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
12205ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            aggregationMode = mContactAggregator.markContactForAggregation(rawContactId);
1221a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1222a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            db.setTransactionSuccessful();
1223a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        } finally {
1224a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            db.endTransaction();
1225a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
1226a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
1227f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        triggerAggregation(id, aggregationMode);
1228a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        return id;
12294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
12304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
12315ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private void triggerAggregation(long rawContactId, int aggregationMode) {
1232f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        switch (aggregationMode) {
12336cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DEFAULT:
1234f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                mContactAggregator.schedule();
1235f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
1236f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
12376cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_IMMEDITATE:
12385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                mContactAggregator.aggregateContact(rawContactId);
1239f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
1240f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
12416cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DISABLED:
1242f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                // Do nothing
1243f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
1244f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        }
1245f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
1246f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
1247a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
12485ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * Returns the group id of the group with sourceId and the same account as rawContactId.
12499261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * If the group doesn't already exist then it is first created,
12509261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param db SQLiteDatabase to use for this operation
12515ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * @param rawContactId the contact this group is associated with
12529261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param sourceId the sourceIf of the group to query or create
12539261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @return the group id of the existing or created group
12549261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalArgumentException if the contact is not associated with an account
12559261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalStateException if a group needs to be created but the creation failed
12569261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     */
12575ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private long getOrMakeGroup(SQLiteDatabase db, long rawContactId, String sourceId) {
12589261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        Account account = null;
12596cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Cursor c = db.query(ContactsQuery.TABLE, ContactsQuery.PROJECTION, RawContacts._ID + "="
12605ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                + rawContactId, null, null, null, null);
12619261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
12629261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            if (c.moveToNext()) {
126367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                final String accountName = c.getString(ContactsQuery.ACCOUNT_NAME);
126467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                final String accountType = c.getString(ContactsQuery.ACCOUNT_TYPE);
12659261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
12669261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    account = new Account(accountName, accountType);
12679261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
12689261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
12699261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
12709261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
12719261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
12729261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        if (account == null) {
12739261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            throw new IllegalArgumentException("if the groupmembership only "
12749261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "has a sourceid the the contact must be associate with "
12759261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "an account");
12769261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
12779261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
12789261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // look up the group that contains this sourceId and has the same account name and type
12795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        // as the contact refered to by rawContactId
12806cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        c = db.query(Tables.GROUPS, new String[]{RawContacts._ID},
12819261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Clauses.GROUP_HAS_ACCOUNT_AND_SOURCE_ID,
12829261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                new String[]{sourceId, account.mName, account.mType}, null, null, null);
12839261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
12849261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            if (c.moveToNext()) {
12859261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                return c.getLong(0);
12869261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            } else {
12879261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                ContentValues groupValues = new ContentValues();
12889261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                groupValues.put(Groups.ACCOUNT_NAME, account.mName);
12899261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                groupValues.put(Groups.ACCOUNT_TYPE, account.mType);
12909261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                groupValues.put(Groups.SOURCE_ID, sourceId);
12919261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                long groupId = db.insert(Tables.GROUPS, Groups.ACCOUNT_NAME, groupValues);
12929261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (groupId < 0) {
12939261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    throw new IllegalStateException("unable to create a new group with "
12949261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            + "this sourceid: " + groupValues);
12959261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
12969261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                return groupId;
12979261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
12989261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
12999261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
13009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
13019261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    }
13029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
13039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /**
130420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     * Delete data row by row so that fixing of primaries etc work correctly.
130520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     */
130620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private int deleteData(String selection, String[] selectionArgs) {
130720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
130820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int count = 0;
130920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        db.beginTransaction();
131020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        try {
131120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
131220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            // Note that the query will return data according to the access restrictions,
131320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            // so we don't need to worry about deleting data we don't have permission to read.
131420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            Cursor c = query(Data.CONTENT_URI, DataIdQuery.COLUMNS, selection, selectionArgs, null);
131520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            try {
131620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                while(c.moveToNext()) {
131720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    long dataId = c.getLong(DataIdQuery._ID);
131820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    count += deleteData(dataId);
131920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                }
132020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            } finally {
132120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                c.close();
132220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
132320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            db.setTransactionSuccessful();
132420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
132520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            db.endTransaction();
132620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
132720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
132820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        return count;
132920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
133020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
133120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    public int deleteData(long dataId, String[] allowedMimeTypes) {
133220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
133320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        Cursor c = db.query(DataQuery.TABLE, DataQuery.COLUMNS,
133420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                DataColumns.CONCRETE_ID + "=" + dataId, null, null, null, null);
133520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // TODO apply restrictions
133620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        try {
133720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!c.moveToFirst()) {
133820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                return 0;
133920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
134020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
134120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            String mimeType = c.getString(DataQuery.MIMETYPE);
134220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            boolean valid = false;
134320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            for (int i = 0; i < allowedMimeTypes.length; i++) {
134420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                if (TextUtils.equals(mimeType, allowedMimeTypes[i])) {
134520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    valid = true;
134620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    break;
134720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                }
134820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
134920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
135020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!valid) {
135120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                throw new RuntimeException("Data type mismatch: expected "
135220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                        + Lists.newArrayList(allowedMimeTypes));
135320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
135420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
135520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            return getDataRowHandler(mimeType).delete(db, c);
135620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
135720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            c.close();
135820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
135920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
136020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
136120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    /**
1362d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov     * Delete the given {@link Data} row, fixing up any {@link Contacts}
1363ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * primaries that reference it.
1364ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
1365ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private int deleteData(long dataId) {
1366ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1367ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1368ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final long mimePhone = mOpenHelper.getMimeTypeId(Phone.CONTENT_ITEM_TYPE);
1369ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final long mimeEmail = mOpenHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE);
1370ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1371ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Check to see if the data about to be deleted was a super-primary on
1372ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // the parent aggregate, and set flags to fix-up once deleted.
1373ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        long aggId = -1;
1374ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        long mimeId = -1;
1375ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        String dataRaw = null;
1376ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        boolean fixOptimal = false;
1377ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        boolean fixFallback = false;
1378ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1379ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Cursor cursor = null;
1380ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        try {
1381d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            cursor = db.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION,
138267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                    DataColumns.CONCRETE_ID + "=" + dataId, null, null, null, null);
1383ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            if (cursor.moveToFirst()) {
1384d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                aggId = cursor.getLong(DataContactsQuery.CONTACT_ID);
1385d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                mimeId = cursor.getLong(DataContactsQuery.MIMETYPE_ID);
1386ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                if (mimeId == mimePhone) {
1387d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    dataRaw = cursor.getString(DataContactsQuery.PHONE_NUMBER);
1388d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    fixOptimal = (cursor.getLong(DataContactsQuery.OPTIMAL_PHONE_ID) == dataId);
1389d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    fixFallback = (cursor.getLong(DataContactsQuery.FALLBACK_PHONE_ID) == dataId);
1390ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                } else if (mimeId == mimeEmail) {
1391d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    dataRaw = cursor.getString(DataContactsQuery.EMAIL_DATA);
1392d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    fixOptimal = (cursor.getLong(DataContactsQuery.OPTIMAL_EMAIL_ID) == dataId);
1393d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    fixFallback = (cursor.getLong(DataContactsQuery.FALLBACK_EMAIL_ID) == dataId);
1394ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                }
1395ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1396ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        } finally {
1397ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            if (cursor != null) {
1398ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                cursor.close();
1399ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                cursor = null;
1400ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1401ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        }
1402ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1403ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Delete the requested data item.
1404ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        int dataDeleted = db.delete(Tables.DATA, Data._ID + "=" + dataId, null);
1405ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1406ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Fix-up any super-primary values that are now invalid.
1407ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        if (fixOptimal || fixFallback) {
1408ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            final ContentValues values = new ContentValues();
1409ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            final StringBuilder scoreClause = new StringBuilder();
1410ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1411ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            final String SCORE = "score";
1412ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1413ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            // Build scoring clause that will first pick data items under the
1414ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            // same aggregate that have identical values, otherwise fall back to
1415ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            // normal primary scoring from the member contacts.
1416ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            scoreClause.append("(CASE WHEN ");
1417ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            if (mimeId == mimePhone) {
1418ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                scoreClause.append(Phone.NUMBER);
1419ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            } else if (mimeId == mimeEmail) {
1420ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                scoreClause.append(Email.DATA);
1421ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1422ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            scoreClause.append("=");
1423ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            DatabaseUtils.appendEscapedSQLString(scoreClause, dataRaw);
1424ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            scoreClause.append(" THEN 2 ELSE " + Data.IS_PRIMARY + " END) AS " + SCORE);
1425ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1426ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            final String[] PROJ_PRIMARY = new String[] {
1427ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                    DataColumns.CONCRETE_ID,
14286cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                    RawContacts.IS_RESTRICTED,
1429ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                    scoreClause.toString(),
1430ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            };
1431ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1432ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            final int COL_DATA_ID = 0;
1433ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            final int COL_IS_RESTRICTED = 1;
143467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            final int COL_SCORE = 2;
1435ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1436d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            cursor = db.query(Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS, PROJ_PRIMARY,
1437d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    ContactsColumns.CONCRETE_ID + "=" + aggId + " AND " + DataColumns.MIMETYPE_ID
1438ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                            + "=" + mimeId, null, null, null, SCORE);
1439ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1440ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            if (fixOptimal) {
1441ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                String colId = null;
144267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                String colIsRestricted = null;
1443ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                if (mimeId == mimePhone) {
1444d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    colId = ContactsColumns.OPTIMAL_PRIMARY_PHONE_ID;
1445d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    colIsRestricted = ContactsColumns.OPTIMAL_PRIMARY_PHONE_IS_RESTRICTED;
1446ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                } else if (mimeId == mimeEmail) {
1447d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    colId = ContactsColumns.OPTIMAL_PRIMARY_EMAIL_ID;
1448d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    colIsRestricted = ContactsColumns.OPTIMAL_PRIMARY_EMAIL_IS_RESTRICTED;
1449ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                }
1450ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1451ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                // Start by replacing with null, since fixOptimal told us that
1452ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                // the previous aggregate values are bad.
1453ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                values.putNull(colId);
145467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                values.putNull(colIsRestricted);
1455ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1456ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                // When finding a new optimal primary, we only care about the
1457ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                // highest scoring value, regardless of source.
1458ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                if (cursor.moveToFirst()) {
1459ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                    final long newOptimal = cursor.getLong(COL_DATA_ID);
146067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                    final long newIsRestricted = cursor.getLong(COL_IS_RESTRICTED);
1461ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1462ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                    if (newOptimal != 0) {
1463ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                        values.put(colId, newOptimal);
1464ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                    }
146567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                    if (newIsRestricted != 0) {
146667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                        values.put(colIsRestricted, newIsRestricted);
1467ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                    }
1468ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                }
1469ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1470ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1471ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            if (fixFallback) {
1472ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                String colId = null;
1473ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                if (mimeId == mimePhone) {
1474d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    colId = ContactsColumns.FALLBACK_PRIMARY_PHONE_ID;
1475ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                } else if (mimeId == mimeEmail) {
1476d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    colId = ContactsColumns.FALLBACK_PRIMARY_EMAIL_ID;
1477ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                }
1478ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1479ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                // Start by replacing with null, since fixFallback told us that
1480ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                // the previous aggregate values are bad.
1481ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                values.putNull(colId);
1482ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1483ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                // The best fallback value is the highest scoring data item that
1484ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                // hasn't been restricted.
1485ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                cursor.moveToPosition(-1);
1486ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                while (cursor.moveToNext()) {
1487ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                    final boolean isRestricted = (cursor.getInt(COL_IS_RESTRICTED) == 1);
1488ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                    if (!isRestricted) {
1489ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                        values.put(colId, cursor.getLong(COL_DATA_ID));
1490ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                        break;
1491ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                    }
1492ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                }
1493ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1494ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1495d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            // Push through any contact updates we have
1496ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            if (values.size() > 0) {
1497d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                db.update(Tables.CONTACTS, values, ContactsColumns.CONCRETE_ID + "=" + aggId,
1498ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                        null);
1499ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1500ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        }
1501ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1502ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return dataDeleted;
1503ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
1504ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1505ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
1506ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Inserts an item in the groups table
1507ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
1508ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private long insertGroup(ContentValues values, Account account) {
1509ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1510ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1511ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        ContentValues overriddenValues = new ContentValues(values);
1512ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        if (!resolveAccount(overriddenValues, account)) {
1513ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            return -1;
1514ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        }
1515ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1516ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Replace package with internal mapping
151767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        final String packageName = overriddenValues.getAsString(Groups.RES_PACKAGE);
151867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        if (packageName != null) {
151967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            overriddenValues.put(GroupsColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
152067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        }
152167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        overriddenValues.remove(Groups.RES_PACKAGE);
1522ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1523ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return db.insert(Tables.GROUPS, Groups.TITLE, overriddenValues);
1524ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
1525ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1526ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
15271f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     * Inserts a presence update.
15281f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     */
152970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    public long insertPresence(ContentValues values) {
15301f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
15311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        final String handle = values.getAsString(Presence.IM_HANDLE);
15321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        final String protocol = values.getAsString(Presence.IM_PROTOCOL);
15331f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        if (TextUtils.isEmpty(handle) || TextUtils.isEmpty(protocol)) {
15341f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            throw new IllegalArgumentException("IM_PROTOCOL and IM_HANDLE are required");
15351f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
15361f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
15371f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        // TODO: generalize to allow other providers to match against email
1538a01e50cb1a5dd21293f8a8fe43f3fe0bf6349164Jeff Sharkey        boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == Integer.parseInt(protocol);
15391f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
154070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        StringBuilder selection = new StringBuilder();
15411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String[] selectionArgs;
15421f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        if (matchEmail) {
154370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            selection.append("(" + Clauses.WHERE_IM_MATCHES + ") OR ("
154470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                    + Clauses.WHERE_EMAIL_MATCHES + ")");
15451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            selectionArgs = new String[] { protocol, handle, handle };
15461f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } else {
154770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            selection.append(Clauses.WHERE_IM_MATCHES);
15481f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            selectionArgs = new String[] { protocol, handle };
15491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
15501f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
155170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (values.containsKey(Presence.DATA_ID)) {
155270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            selection.append(" AND " + DataColumns.CONCRETE_ID + "=")
155370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                    .append(values.getAsLong(Presence.DATA_ID));
155470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
155570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
15565ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        if (values.containsKey(Presence.RAW_CONTACT_ID)) {
1557d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            selection.append(" AND " + DataColumns.CONCRETE_RAW_CONTACT_ID + "=")
15585ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    .append(values.getAsLong(Presence.RAW_CONTACT_ID));
155970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
156070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
156170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        selection.append(" AND ").append(getContactsRestrictionExceptions());
156270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
15631f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        long dataId = -1;
15645ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        long rawContactId = -1;
156570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
15661f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        Cursor cursor = null;
15671f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        try {
156870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            cursor = db.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION,
156970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                    selection.toString(), selectionArgs, null, null, null);
15701f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            if (cursor.moveToFirst()) {
157167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                dataId = cursor.getLong(DataContactsQuery.DATA_ID);
15725ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID);
15731f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            } else {
15741f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                // No contact found, return a null URI
15751f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                return -1;
15761f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
15771f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } finally {
157831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            if (cursor != null) {
157931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                cursor.close();
158031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
15811f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
15821f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
15831f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        values.put(Presence.DATA_ID, dataId);
15845ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        values.put(Presence.RAW_CONTACT_ID, rawContactId);
15851f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
15861f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        // Insert the presence update
15871f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        long presenceId = db.replace(Tables.PRESENCE, null, values);
15881f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        return presenceId;
15891f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    }
15901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
15914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
15924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public int delete(Uri uri, String selection, String[] selectionArgs) {
1593508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1594508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        final int match = sUriMatcher.match(uri);
1595508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        switch (match) {
159635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
159735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                return mOpenHelper.getSyncState().delete(db, selection, selectionArgs);
159835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1599d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
1600d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
16016bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
1602d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                // Remove references to the contact first
16036bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                ContentValues values = new ContentValues();
1604d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values.putNull(RawContacts.CONTACT_ID);
16055ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                db.update(Tables.RAW_CONTACTS, values,
1606d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        RawContacts.CONTACT_ID + "=" + contactId, null);
16076bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
1608d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                return db.delete(Tables.CONTACTS, BaseColumns._ID + "=" + contactId, null);
16096bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
16106bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
16115ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
161233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                return deleteRawContact(uri);
1613508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
1614508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
161520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
161620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                return deleteData(selection, selectionArgs);
161720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
161820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1619508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            case DATA_ID: {
1620508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey                long dataId = ContentUris.parseId(uri);
1621ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                return deleteData(dataId);
1622ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1623ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1624ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
1625ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
1626ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                final long groupMembershipMimetypeId = mOpenHelper
1627ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                        .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
1628ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                int groupsDeleted = db.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null);
1629ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                int dataDeleted = db.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "="
1630ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                        + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "="
1631ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                        + groupId, null);
1632ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                mOpenHelper.updateAllVisible();
1633ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                return groupsDeleted + dataDeleted;
1634508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
1635508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
16361f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            case PRESENCE: {
16371f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                return db.delete(Tables.PRESENCE, null, null);
16381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
16391f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
1640508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            default:
16413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                return mLegacyApiSupport.delete(uri, selection, selectionArgs);
1642508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        }
16434f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
16444f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
164533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    private int deleteRawContact(Uri uri) {
164633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        boolean permanentDeletion = false;
164733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        String permanent = uri.getQueryParameter(RawContacts.DELETE_PERMANENTLY);
164833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        if (permanent != null && !"false".equals(permanent.toLowerCase())) {
164933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov            permanentDeletion = true;
165033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        }
165133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
16525ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        long rawContactId = ContentUris.parseId(uri);
16535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        return deleteRawContact(rawContactId, permanentDeletion);
165433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
165533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
16565ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public int deleteRawContact(long rawContactId, boolean permanently) {
165733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
165833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
1659c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        // TODO delete aggregation exceptions
1660c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        mOpenHelper.removeContactIfSingleton(rawContactId);
166133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        if (permanently) {
1662373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov            db.delete(Tables.PRESENCE, Presence.RAW_CONTACT_ID + "=" + rawContactId, null);
16635ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return db.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null);
166433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        } else {
166533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov            mValues.clear();
166633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov            mValues.put(RawContacts.DELETED, true);
1667c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
1668c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            mValues.putNull(RawContacts.CONTACT_ID);
16695ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return updateRawContact(rawContactId, mValues, null, null);
167033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        }
167133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
167233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
1673f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana    private static Account readAccountFromQueryParams(Uri uri) {
16746cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String name = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
16756cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        final String type = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
1676f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(type)) {
1677f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana            return null;
1678f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        }
1679f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        return new Account(name, type);
1680f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana    }
1681f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana
1682ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
16834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
16844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
168500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
168635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        int count = 0;
168700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
168800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        final int match = sUriMatcher.match(uri);
168900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        switch(match) {
169035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
169135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                return mOpenHelper.getSyncState().update(db, values, selection, selectionArgs);
169235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1693d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            // TODO(emillar): We will want to disallow editing the contacts table at some point.
1694d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
1695d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                count = db.update(Tables.CONTACTS, values, selection, selectionArgs);
169600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
169700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
169800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
1699d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
1700d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                count = updateContactData(db, ContentUris.parseId(uri), values);
1701c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                break;
1702c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar            }
1703c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
170420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
170520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                count = updateData(values, selection, selectionArgs);
170620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                break;
170720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
1708c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
170920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA_ID: {
171020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                count = updateData(ContentUris.parseId(uri), values);
171100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
171200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
17137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
17145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
17155ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                count = db.update(Tables.RAW_CONTACTS, values, selection, selectionArgs);
17167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
17177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
17187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
17195ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
172033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
172133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                count = updateRawContact(rawContactId, values, selection, selectionArgs);
17227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
17237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
17247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
1725ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
1726ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                count = db.update(Tables.GROUPS, values, selection, selectionArgs);
1727ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                mOpenHelper.updateAllVisible();
1728ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
1729ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1730ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1731ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
1732ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
1733ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                String selectionWithId = (Groups._ID + "=" + groupId + " ")
1734ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                        + (selection == null ? "" : " AND " + selection);
1735ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                count = db.update(Tables.GROUPS, values, selectionWithId, selectionArgs);
1736ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1737d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                // If changing visibility, then update contacts
1738ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                if (values.containsKey(Groups.GROUP_VISIBLE)) {
1739ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                    mOpenHelper.updateAllVisible();
1740ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                }
1741ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1742ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
1743ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
1744ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
1745127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
1746127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                count = updateAggregationException(db, 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        if (count > 0) {
175500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            getContext().getContentResolver().notifyChange(uri, null);
175600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        }
175700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        return count;
17584f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
17594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
17605ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private int updateRawContact(long rawContactId, ContentValues values, String selection,
176133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov            String[] selectionArgs) {
176233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
17635ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        String selectionWithId = (RawContacts._ID + " = " + rawContactId + " ")
176433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                + (selection == null ? "" : " AND " + selection);
17655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        return db.update(Tables.RAW_CONTACTS, values, selectionWithId, selectionArgs);
176633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
176733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
176820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private int updateData(ContentValues values, String selection,
176920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            String[] selectionArgs) {
177020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
177120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int count = 0;
177220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        db.beginTransaction();
177320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        try {
177420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
177520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            // Note that the query will return data according to the access restrictions,
177620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            // so we don't need to worry about deleting data we don't have permission to read.
177720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            Cursor c = query(Data.CONTENT_URI, DataIdQuery.COLUMNS, selection, selectionArgs, null);
177820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            try {
177920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                while(c.moveToNext()) {
178020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    long dataId = c.getLong(DataIdQuery._ID);
178120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    count += updateData(dataId, values);
178220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                }
178320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            } finally {
178420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                c.close();
178520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
178620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            db.setTransactionSuccessful();
178720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
178820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            db.endTransaction();
178920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
179020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
179120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        return count;
179220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
179320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
179420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private int updateData(long dataId, ContentValues values) {
179520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
179620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
179720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.clear();
179820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.putAll(values);
179920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data._ID);
18005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mValues.remove(Data.RAW_CONTACT_ID);
180120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
180220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
180320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        String packageName = values.getAsString(Data.RES_PACKAGE);
180420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        if (packageName != null) {
180520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.remove(Data.RES_PACKAGE);
180620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName));
180720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
180820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
180970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsSuperPrimary = mValues.containsKey(Data.IS_SUPER_PRIMARY);
181070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        boolean containsIsPrimary = mValues.containsKey(Data.IS_PRIMARY);
181120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
181220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // Remove primary or super primary values being set to 0. This is disallowed by the
181320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        // content provider.
181470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsSuperPrimary && mValues.getAsInteger(Data.IS_SUPER_PRIMARY) == 0) {
181520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsSuperPrimary = false;
181670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_SUPER_PRIMARY);
181720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
181870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (containsIsPrimary && mValues.getAsInteger(Data.IS_PRIMARY) == 0) {
181920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            containsIsPrimary = false;
182070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_PRIMARY);
182120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
182220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
182320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        if (containsIsSuperPrimary) {
182420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            setIsSuperPrimary(dataId);
182520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            setIsPrimary(dataId);
182620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
182720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            // Now that we've taken care of setting these, remove them from "values".
182870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_SUPER_PRIMARY);
182920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (containsIsPrimary) {
183070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov                mValues.remove(Data.IS_PRIMARY);
183120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
183220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } else if (containsIsPrimary) {
183320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            setIsPrimary(dataId);
183420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
183520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            // Now that we've taken care of setting this, remove it from "values".
183670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            mValues.remove(Data.IS_PRIMARY);
183720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
183820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
183970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (mValues.size() > 0) {
184070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return db.update(Tables.DATA, mValues, Data._ID + " = " + dataId, null);
184120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
184220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        return 0;
184320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
184420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
1845d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private int updateContactData(SQLiteDatabase db, long contactId, ContentValues values) {
1846d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
1847d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // First update all constituent contacts
1848f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        ContentValues optionValues = new ContentValues(5);
18496cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyStringValue(optionValues, RawContacts.CUSTOM_RINGTONE,
1850d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.CUSTOM_RINGTONE);
18516cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.SEND_TO_VOICEMAIL,
1852d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.SEND_TO_VOICEMAIL);
18536cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.LAST_TIME_CONTACTED,
1854d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.LAST_TIME_CONTACTED);
18556cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.TIMES_CONTACTED,
1856d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.TIMES_CONTACTED);
18576cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        OpenHelper.copyLongValue(optionValues, RawContacts.STARRED,
1858d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.STARRED);
1859d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
1860d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // Nothing to update - just return
1861d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        if (optionValues.size() == 0) {
1862d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov            return 0;
1863d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        }
1864d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
18655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        db.update(Tables.RAW_CONTACTS, optionValues,
1866d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                RawContacts.CONTACT_ID + "=" + contactId, null);
1867d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        return db.update(Tables.CONTACTS, values, Contacts._ID + "=" + contactId, null);
1868f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
1869d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
1870d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    public void updateContactTime(long contactId, long lastTimeContacted) {
1871f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        mLastTimeContactedUpdate.bindLong(1, lastTimeContacted);
1872d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        mLastTimeContactedUpdate.bindLong(2, contactId);
1873f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        mLastTimeContactedUpdate.execute();
1874d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov    }
1875d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
18765ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static class RawContactPair {
18775ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        final long rawContactId1;
18785ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        final long rawContactId2;
1879127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
1880127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        /**
18815ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov         * Constructor that ensures that this.rawContactId1 &lt; this.rawContactId2
1882127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov         */
18835ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public RawContactPair(long rawContactId1, long rawContactId2) {
18845ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            if (rawContactId1 < rawContactId2) {
18855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId1 = rawContactId1;
18865ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId2 = rawContactId2;
1887127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            } else {
18885ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId2 = rawContactId1;
18895ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                this.rawContactId1 = rawContactId2;
1890127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            }
1891127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        }
1892127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov    }
189380c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
1894127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov    private int updateAggregationException(SQLiteDatabase db, ContentValues values) {
1895127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        int exceptionType = values.getAsInteger(AggregationExceptions.TYPE);
1896d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        long contactId = values.getAsInteger(AggregationExceptions.CONTACT_ID);
18975ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        long rawContactId = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID);
189880c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
1899d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        // First, we build a list of contactID-contactID pairs for the given contact and contact.
19005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        ArrayList<RawContactPair> pairs = new ArrayList<RawContactPair>();
1901d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        Cursor c = db.query(ContactsQuery.TABLE, ContactsQuery.PROJECTION, RawContacts.CONTACT_ID
1902d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                + "=" + contactId, null, null, null, null);
1903127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        try {
1904127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            while (c.moveToNext()) {
19055ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long aggregatedContactId = c.getLong(ContactsQuery.RAW_CONTACT_ID);
19065ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                if (aggregatedContactId != rawContactId) {
19075ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    pairs.add(new RawContactPair(aggregatedContactId, rawContactId));
1908e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov                }
1909b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
1910b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        } finally {
1911b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            c.close();
1912b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        }
1913127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
1914127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // Now we iterate through all contact pairs to see if we need to insert/delete/update
1915127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // the corresponding exception
1916127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        ContentValues exceptionValues = new ContentValues(3);
1917127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        exceptionValues.put(AggregationExceptions.TYPE, exceptionType);
19185ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        for (RawContactPair pair : pairs) {
1919127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            final String whereClause =
19205ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    AggregationExceptionColumns.RAW_CONTACT_ID1 + "=" + pair.rawContactId1 + " AND "
19215ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + AggregationExceptionColumns.RAW_CONTACT_ID2 + "=" + pair.rawContactId2;
1922127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) {
1923127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                db.delete(Tables.AGGREGATION_EXCEPTIONS, whereClause, null);
1924127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            } else {
19255ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                exceptionValues.put(AggregationExceptionColumns.RAW_CONTACT_ID1, pair.rawContactId1);
19265ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                exceptionValues.put(AggregationExceptionColumns.RAW_CONTACT_ID2, pair.rawContactId2);
1927127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID,
1928127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                        exceptionValues);
1929127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            }
1930127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        }
1931127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
19325ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        int aggregationMode = mContactAggregator.markContactForAggregation(rawContactId);
19336cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        if (aggregationMode != RawContacts.AGGREGATION_MODE_DISABLED) {
19345ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            mContactAggregator.aggregateContact(db, rawContactId);
1935f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC
1936f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                    || exceptionType == AggregationExceptions.TYPE_KEEP_OUT) {
1937d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                mContactAggregator.updateAggregateData(contactId);
1938f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            }
19397a39bf269294a8130ddd463460b9b36cf4ff74a8Dmitri Plotnikov        }
1940127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
1941127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // The return value is fake - we just confirm that we made a change, not count actual
1942127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // rows changed.
1943127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        return 1;
1944b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    }
1945b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
1946619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
1947619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Test if a {@link String} value appears in the given list.
1948619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
1949619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private boolean isContained(String[] array, String value) {
1950bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        if (array != null) {
1951bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar            for (String test : array) {
1952bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar                if (value.equals(test)) {
1953bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar                    return true;
1954bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar                }
1955619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            }
1956619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
1957619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        return false;
1958619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
1959619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
1960619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
1961619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Test if a {@link String} value appears in the given list, and add to the
1962619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * array if the value doesn't already appear.
1963619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
1964619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private String[] assertContained(String[] array, String value) {
1965bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        if (array == null) {
1966bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar            array = new String[] {value};
1967bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar        } else if (!isContained(array, value)) {
1968619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            String[] newArray = new String[array.length + 1];
1969619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            System.arraycopy(array, 0, newArray, 0, array.length);
1970619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            newArray[array.length] = value;
1971619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            array = newArray;
1972619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
1973619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        return array;
1974619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
1975619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
19764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
19774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
19784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            String sortOrder) {
19794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
198035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1981d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
19821f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String groupBy = null;
1983c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limit = getLimit(uri);
1984c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
1985d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        String contactIdColName = Tables.CONTACTS + "." + Contacts._ID;
19864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1987619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // TODO: Consider writing a test case for RestrictionExceptions when you
1988619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // write a new query() block to make sure it protects restricted data.
1989a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
19904f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
199135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
199235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                return mOpenHelper.getSyncState().query(db, projection, selection,  selectionArgs,
199335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                        sortOrder);
199435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1995d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
1996d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.CONTACTS);
1997619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                applyAggregateRestrictionExceptions(qb);
1998d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                applyAggregatePrimaryRestrictionExceptions(sContactsProjectionMap);
1999d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsProjectionMap);
2000619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                break;
2001619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            }
2002619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2003d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
2004619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                long aggId = ContentUris.parseId(uri);
2005d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.CONTACTS);
2006d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.appendWhere(ContactsColumns.CONCRETE_ID + "=" + aggId + " AND ");
2007619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                applyAggregateRestrictionExceptions(qb);
2008d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                applyAggregatePrimaryRestrictionExceptions(sContactsProjectionMap);
2009d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsProjectionMap);
20106bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
20116bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
20126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
2013d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY: {
2014619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                // TODO: join into social status tables
2015d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.CONTACTS_JOIN_PRESENCE_PRIMARY_PHONE);
2016619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                applyAggregateRestrictionExceptions(qb);
2017d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                applyAggregatePrimaryRestrictionExceptions(sContactsSummaryProjectionMap);
2018d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                projection = assertContained(projection, Contacts.PRIMARY_PHONE_ID);
2019d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
2020d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                groupBy = contactIdColName;
20211f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                break;
20221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
20231f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2024d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY_ID: {
2025619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                // TODO: join into social status tables
20261f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                long aggId = ContentUris.parseId(uri);
2027d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.CONTACTS_JOIN_PRESENCE_PRIMARY_PHONE);
2028d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.appendWhere(ContactsColumns.CONCRETE_ID + "=" + aggId + " AND ");
2029619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                applyAggregateRestrictionExceptions(qb);
2030d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                applyAggregatePrimaryRestrictionExceptions(sContactsSummaryProjectionMap);
2031d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                projection = assertContained(projection, Contacts.PRIMARY_PHONE_ID);
2032d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
2033d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                groupBy = contactIdColName;
20341f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                break;
20351f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
20361f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2037d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY_FILTER: {
2038619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                // TODO: filter query based on callingUid
2039d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.CONTACTS_JOIN_PRESENCE_PRIMARY_PHONE);
2040d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
2041ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
2042d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    qb.appendWhere(buildContactLookupWhereClause(uri.getLastPathSegment()));
2043ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
2044d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                groupBy = contactIdColName;
2045ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2046ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2047ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
2048d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY_STREQUENT_FILTER:
2049d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY_STREQUENT: {
2050d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Build the first query for starred
2051d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.CONTACTS_JOIN_PRESENCE_PRIMARY_PHONE);
2052d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
2053d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                if (match == CONTACTS_SUMMARY_STREQUENT_FILTER
2054d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        && uri.getPathSegments().size() > 3) {
2055d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    qb.appendWhere(buildContactLookupWhereClause(uri.getLastPathSegment()));
2056d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2057d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                final String starredQuery = qb.buildQuery(projection, Contacts.STARRED + "=1",
2058d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        null, contactIdColName, null, null,
2059d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        null /* limit */);
2060d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2061d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Build the second query for frequent
2062d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                qb = new SQLiteQueryBuilder();
2063d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.CONTACTS_JOIN_PRESENCE_PRIMARY_PHONE);
2064d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
2065d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                if (match == CONTACTS_SUMMARY_STREQUENT_FILTER
2066d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        && uri.getPathSegments().size() > 3) {
2067d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    qb.appendWhere(buildContactLookupWhereClause(uri.getLastPathSegment()));
2068d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2069d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String frequentQuery = qb.buildQuery(projection,
2070d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        Contacts.TIMES_CONTACTED + " > 0 AND (" + Contacts.STARRED
2071d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        + " = 0 OR " + Contacts.STARRED + " IS NULL)",
2072d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        null, contactIdColName, null, null, null);
2073d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2074d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Put them together
2075d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery},
2076d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        STREQUENT_ORDER_BY, STREQUENT_LIMIT);
2077d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                Cursor c = db.rawQueryWithFactory(null, query, null,
2078d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        Tables.CONTACTS_JOIN_PRESENCE_PRIMARY_PHONE);
2079d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2080d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                if ((c != null) && !isTemporary()) {
2081d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                    c.setNotificationUri(getContext().getContentResolver(),
2082d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                            ContactsContract.AUTHORITY_URI);
2083d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
2084d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                return c;
2085d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar            }
2086d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
2087d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_SUMMARY_GROUP: {
2088d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.CONTACTS_JOIN_PRESENCE_PRIMARY_PHONE);
2089b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                applyAggregateRestrictionExceptions(qb);
2090d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                applyAggregatePrimaryRestrictionExceptions(sContactsSummaryProjectionMap);
2091d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                projection = assertContained(projection, Contacts.PRIMARY_PHONE_ID);
2092d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sContactsSummaryProjectionMap);
2093b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                if (uri.getPathSegments().size() > 2) {
2094d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    qb.appendWhere(" AND " + sContactsInGroupSelect);
2095b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                    selectionArgs = appendGroupArg(selectionArgs, uri.getLastPathSegment());
2096b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                }
2097d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                groupBy = contactIdColName;
2098b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                break;
2099b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            }
2100b67163a1088f09c59f324350662eb18772fac6b6Evan Millar
2101d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_DATA: {
2102619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                long aggId = Long.parseLong(uri.getPathSegments().get(1));
2103d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_RAW_CONTACTS_CONTACTS_GROUPS);
21040c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar                qb.setProjectionMap(sDataRawContactsGroupsContactProjectionMap);
2105d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.appendWhere(RawContacts.CONTACT_ID + "=" + aggId + " AND ");
2106619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                applyDataRestrictionExceptions(qb);
21076bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
21086bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
210900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
21102815f58f72f109790585931f601a63ddc02536a5Evan Millar            case CONTACTS_RAW_CONTACTS: {
21112815f58f72f109790585931f601a63ddc02536a5Evan Millar                long contactId = Long.parseLong(uri.getPathSegments().get(1));
21122815f58f72f109790585931f601a63ddc02536a5Evan Millar                qb.setTables(Tables.RAW_CONTACTS_JOIN_CONTACTS);
21132815f58f72f109790585931f601a63ddc02536a5Evan Millar                qb.setProjectionMap(sRawContactsContactsProjectionMap);
21142815f58f72f109790585931f601a63ddc02536a5Evan Millar                qb.appendWhere(RawContacts.CONTACT_ID + "=" + contactId + " AND ");
21152815f58f72f109790585931f601a63ddc02536a5Evan Millar                applyDataRestrictionExceptions(qb);
21162815f58f72f109790585931f601a63ddc02536a5Evan Millar                break;
21172815f58f72f109790585931f601a63ddc02536a5Evan Millar            }
21182815f58f72f109790585931f601a63ddc02536a5Evan Millar
2119ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case PHONES_FILTER: {
2120d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_RAW_CONTACTS_CONTACTS);
21210c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar                qb.setProjectionMap(sDataRawContactsContactProjectionMap);
2122ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                qb.appendWhere(Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
2123ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
2124d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    qb.appendWhere(" AND " + buildContactLookupWhereClause(
2125ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                            uri.getLastPathSegment()));
2126ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
2127ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2128ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2129ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2130ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case PHONES: {
2131d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_RAW_CONTACTS_CONTACTS);
21320c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar                qb.setProjectionMap(sDataRawContactsContactProjectionMap);
2133ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                qb.appendWhere(Data.MIMETYPE + " = \"" + Phone.CONTENT_ITEM_TYPE + "\"");
2134ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2135ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2136ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
2137ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case POSTALS: {
2138d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_RAW_CONTACTS_CONTACTS);
21390c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar                qb.setProjectionMap(sDataRawContactsContactProjectionMap);
214067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                qb.appendWhere(Data.MIMETYPE + " = \"" + StructuredPostal.CONTENT_ITEM_TYPE + "\"");
2141ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
2142ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
2143ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
21445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
21455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.setTables(Tables.RAW_CONTACTS);
2146d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sRawContactsProjectionMap);
2147619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                applyContactsRestrictionExceptions(qb);
21484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
21494f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
21504f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
21515ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
21525ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
21535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.setTables(Tables.RAW_CONTACTS);
2154d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setProjectionMap(sRawContactsProjectionMap);
21555ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.appendWhere(RawContactsColumns.CONCRETE_ID + "=" + rawContactId + " AND ");
2156619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                applyContactsRestrictionExceptions(qb);
21574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
21584f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
21594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
21605ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
21615ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = Long.parseLong(uri.getPathSegments().get(1));
21625ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_RAW_CONTACTS_GROUPS);
21630c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar                qb.setProjectionMap(sDataRawContactsGroupsProjectionMap);
21645ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.appendWhere(Data.RAW_CONTACT_ID + "=" + rawContactId + " AND ");
2165619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                applyDataRestrictionExceptions(qb);
2166a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
2167a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
2168a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
216928ab0f857caa92402878244d9c5ea2a59e070935Jeff Sharkey            case CONTACTS_FILTER_EMAIL: {
2170619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                // TODO: filter query based on callingUid
2171d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_RAW_CONTACTS_CONTACTS);
21720c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar                qb.setProjectionMap(sDataRawContactsProjectionMap);
21735d0f923eb4c5351ebf323cc6f19c82acff98693eJeff Sharkey                qb.appendWhere(Data.MIMETYPE + "='" + CommonDataKinds.Email.CONTENT_ITEM_TYPE + "'");
2174e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                qb.appendWhere(" AND " + CommonDataKinds.Email.DATA + "=");
2175e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                qb.appendWhereEscapeString(uri.getPathSegments().get(2));
2176e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
2177e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
2178e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
2179e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            case DATA: {
21806cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
21816cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
2182343c56b5679c58bf1835a0e219fff57beae6ecefFred Quintana                if (!TextUtils.isEmpty(accountName)) {
2183226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    qb.appendWhere(RawContactsColumns.CONCRETE_ACCOUNT_NAME + "="
2184035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                            + DatabaseUtils.sqlEscapeString(accountName) + " AND "
2185226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                            + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + "="
2186035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                            + DatabaseUtils.sqlEscapeString(accountType) + " AND ");
2187343c56b5679c58bf1835a0e219fff57beae6ecefFred Quintana                }
21885ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_RAW_CONTACTS_GROUPS);
21899261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                qb.setProjectionMap(sDataGroupsProjectionMap);
2190619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                applyDataRestrictionExceptions(qb);
2191e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
2192e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
2193e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
21944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            case DATA_ID: {
21955ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_RAW_CONTACTS_GROUPS);
21969261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                qb.setProjectionMap(sDataGroupsProjectionMap);
2197ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.appendWhere(DataColumns.CONCRETE_ID + "=" + ContentUris.parseId(uri) + " AND ");
2198619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                applyDataRestrictionExceptions(qb);
21994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
22004f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
22014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
2202a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case PHONE_LOOKUP: {
2203619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                // TODO: filter query based on callingUid
2204a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                if (TextUtils.isEmpty(sortOrder)) {
2205a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // Default the sort order to something reasonable so we get consistent
2206a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // results when callers don't request an ordering
22075ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    sortOrder = Data.RAW_CONTACT_ID;
2208a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                }
2209a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2210a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                final String number = uri.getLastPathSegment();
2211bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov                OpenHelper.buildPhoneLookupQuery(qb, number);
22120c83a3c4b6a9c8a0dfa0b3aa2af91b74d8e3304fEvan Millar                qb.setProjectionMap(sDataRawContactsProjectionMap);
2213a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
2214a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
2215a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2216ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
2217ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2218ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
2219ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2220ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2221ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2222ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
2223ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
2224ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2225ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
2226ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.appendWhere(GroupsColumns.CONCRETE_ID + "=" + groupId);
2227ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2228ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2229ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2230ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_SUMMARY: {
2231d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                qb.setTables(Tables.GROUPS_JOIN_PACKAGES_DATA_RAW_CONTACTS_CONTACTS);
2232ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsSummaryProjectionMap);
2233ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                groupBy = GroupsColumns.CONCRETE_ID;
2234ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2235ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2236ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2237b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
22385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.setTables(Tables.AGGREGATION_EXCEPTIONS_JOIN_RAW_CONTACTS);
2239b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                qb.setProjectionMap(sAggregationExceptionsProjectionMap);
2240b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
2241b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
2242b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
224331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_SUGGESTIONS: {
2244d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
2245c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2246c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                // TODO drop MAX_SUGGESTIONS in favor of LIMIT
224731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                final String maxSuggestionsParam =
224831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                        uri.getQueryParameter(AggregationSuggestions.MAX_SUGGESTIONS);
224931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
225031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                final int maxSuggestions;
225131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                if (maxSuggestionsParam != null) {
225231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                    maxSuggestions = Integer.parseInt(maxSuggestionsParam);
225331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                } else {
225431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                    maxSuggestions = DEFAULT_MAX_SUGGESTIONS;
225531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                }
225631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
2257d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                return mContactAggregator.queryAggregationSuggestions(contactId, projection,
2258d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        sContactsProjectionMap, maxSuggestions);
225931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
226031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
22615ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case PRESENCE: {
2262373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setTables(Tables.PRESENCE);
2263373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setProjectionMap(sPresenceProjectionMap);
22645ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
22655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
22665ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
22675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case PRESENCE_ID: {
2268373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setTables(Tables.PRESENCE);
2269373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.setProjectionMap(sPresenceProjectionMap);
2270373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov                qb.appendWhere(Presence._ID + "=" + ContentUris.parseId(uri));
22715ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
22725ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
22735ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
2274c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS: {
2275a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov                return mGlobalSearchSupport.handleSearchSuggestionsQuery(db, uri, limit);
2276c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
2277c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2278c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT: {
2279c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                // TODO
2280c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                break;
2281c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
2282c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
22834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            default:
2284f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.query(uri, projection, selection, selectionArgs,
2285c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                        sortOrder, limit);
22864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
22874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
22884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        // Perform the query and set the notification uri
22891f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        final Cursor c = qb.query(db, projection, selection, selectionArgs,
2290bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar                groupBy, null, sortOrder, limit);
22914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        if (c != null) {
22924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI);
22934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
22944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        return c;
22954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
22964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
22977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
2298c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * Gets the value of the "limit" URI query parameter.
2299c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *
2300c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * @return A string containing a non-negative integer, or <code>null</code> if
2301c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *         the parameter is not set, or is set to an invalid value.
2302c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     */
2303c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private String getLimit(Uri url) {
2304c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limitParam = url.getQueryParameter("limit");
2305c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limitParam == null) {
2306c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
2307c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
2308c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        // make sure that the limit is a non-negative integer
2309c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        try {
2310c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            int l = Integer.parseInt(limitParam);
2311c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            if (l < 0) {
2312c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                Log.w(TAG, "Invalid limit parameter: " + limitParam);
2313c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return null;
2314c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
2315c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return String.valueOf(l);
2316c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        } catch (NumberFormatException ex) {
2317c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            Log.w(TAG, "Invalid limit parameter: " + limitParam);
2318c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
2319c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
2320c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
2321c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2322c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    /**
23236cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov     * List of package names with access to {@link RawContacts#IS_RESTRICTED} data.
232467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey     */
232567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    private static final String[] sAllowedPackages = new String[] {
232667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        "com.android.contacts",
232767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        "com.facebook",
232867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    };
232967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
233067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    /**
233167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey     * Check if {@link Binder#getCallingUid()} should be allowed access to
23326cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov     * {@link RawContacts#IS_RESTRICTED} data.
233367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey     */
233467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    private boolean hasRestrictedAccess() {
233567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        final PackageManager pm = getContext().getPackageManager();
233667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        final String[] callerPackages = pm.getPackagesForUid(Binder.getCallingUid());
233767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
233867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        // Has restricted access if caller matches any packages
233967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        for (String callerPackage : callerPackages) {
234067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            for (String allowedPackage : sAllowedPackages) {
234167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                if (allowedPackage.equals(callerPackage)) {
234267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                    return true;
234367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                }
234467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            }
234567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        }
234667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        return false;
234767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    }
234867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
234967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey    /**
2350d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov     * Restrict selection of {@link Contacts} to only public ones, or those
235167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey     * the caller has been granted an exception to.
2352619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
2353619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private void applyAggregateRestrictionExceptions(SQLiteQueryBuilder qb) {
235467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        if (hasRestrictedAccess()) {
235567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            qb.appendWhere("1");
235667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        } else {
2357d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            qb.appendWhere(ContactsColumns.SINGLE_IS_RESTRICTED + "=0");
2358619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
2359619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
2360619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2361619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
2362619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Find any exceptions that have been granted to the calling process, and
2363d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov     * add projections to correctly select {@link Contacts#PRIMARY_PHONE_ID}
2364d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov     * and {@link Contacts#PRIMARY_EMAIL_ID}.
2365619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
2366619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private void applyAggregatePrimaryRestrictionExceptions(HashMap<String, String> projection) {
236767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        String projectionPhone;
236867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        String projectionEmail;
236967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
237067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        if (hasRestrictedAccess()) {
237167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            // With restricted access, always give optimal values
2372d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            projectionPhone = ContactsColumns.OPTIMAL_PRIMARY_PHONE_ID + " AS "
2373d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    + Contacts.PRIMARY_PHONE_ID;
2374d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            projectionEmail = ContactsColumns.OPTIMAL_PRIMARY_EMAIL_ID + " AS "
2375d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    + Contacts.PRIMARY_EMAIL_ID;
237667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        } else {
237767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey            // With general access, always give fallback values
2378d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            projectionPhone = ContactsColumns.FALLBACK_PRIMARY_PHONE_ID + " AS "
2379d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    + Contacts.PRIMARY_PHONE_ID;
2380d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            projectionEmail = ContactsColumns.FALLBACK_PRIMARY_EMAIL_ID + " AS "
2381d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                    + Contacts.PRIMARY_EMAIL_ID;
238267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        }
238367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
2384d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        projection.remove(Contacts.PRIMARY_PHONE_ID);
2385d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        projection.put(Contacts.PRIMARY_PHONE_ID, projectionPhone);
2386619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2387d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        projection.remove(Contacts.PRIMARY_EMAIL_ID);
2388d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        projection.put(Contacts.PRIMARY_EMAIL_ID, projectionEmail);
2389619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
2390619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2391619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
2392619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Find any exceptions that have been granted to the
2393619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * {@link Binder#getCallingUid()}, and add a limiting clause to the given
2394619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * {@link SQLiteQueryBuilder} to hide restricted data.
2395619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
2396619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private void applyContactsRestrictionExceptions(SQLiteQueryBuilder qb) {
239770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        qb.appendWhere(getContactsRestrictionExceptions());
239870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    }
239970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
2400a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    String getContactsRestrictionExceptions() {
240167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        if (hasRestrictedAccess()) {
240270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
240370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        } else {
24046cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            return RawContacts.IS_RESTRICTED + "=0";
240570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
240670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    }
240770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
240870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    public String getContactsRestrictionExceptionAsNestedQuery(String contactIdColumn) {
240970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        if (hasRestrictedAccess()) {
241070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
241167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        } else {
24125ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return "(SELECT " + RawContacts.IS_RESTRICTED + " FROM " + Tables.RAW_CONTACTS
24135ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + " WHERE " + RawContactsColumns.CONCRETE_ID + "=" + contactIdColumn + ")=0";
2414619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
2415619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
2416619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2417619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
2418619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Find any exceptions that have been granted to the
2419619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * {@link Binder#getCallingUid()}, and add a limiting clause to the given
2420619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * {@link SQLiteQueryBuilder} to hide restricted data.
2421619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
2422e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    void applyDataRestrictionExceptions(SQLiteQueryBuilder qb) {
2423619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        applyContactsRestrictionExceptions(qb);
2424619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
2425619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2426619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
24277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     * An implementation of EntityIterator that joins the contacts and data tables
24287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     * and consumes all the data rows for a contact in order to build the Entity for a contact.
24297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
24307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    private static class ContactsEntityIterator implements EntityIterator {
24317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private final Cursor mEntityCursor;
24327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private volatile boolean mIsClosed;
24337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
24347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private static final String[] DATA_KEYS = new String[]{
24357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                "data1",
24367e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                "data2",
24377e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                "data3",
24387e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                "data4",
24397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                "data5",
24407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                "data6",
24417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                "data7",
24427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                "data8",
24437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                "data9",
244467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                "data10",
244567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                "data11",
244667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                "data12",
244767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                "data13",
244867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                "data14",
244967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                "data15"};
24507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
24517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        private static final String[] PROJECTION = new String[]{
24526cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.ACCOUNT_NAME,
24536cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
24546cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.SOURCE_ID,
24556cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.VERSION,
24566cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.DIRTY,
24576cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data._ID,
24586cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.RES_PACKAGE,
24596cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.MIMETYPE,
24606cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA1,
24616cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA2,
24626cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA3,
24636cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA4,
24646cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA5,
24656cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA6,
24666cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA7,
24676cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA8,
24686cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA9,
24696cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA10,
24706cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA11,
24716cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA12,
24726cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA13,
24736cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA14,
24746cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA15,
24755ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                RawContacts.Data.RAW_CONTACT_ID,
24766cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.IS_PRIMARY,
24776cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                RawContacts.Data.DATA_VERSION,
24789261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                GroupMembership.GROUP_SOURCE_ID};
2479035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana
2480035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_ACCOUNT_NAME = 0;
2481035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_ACCOUNT_TYPE = 1;
2482035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_SOURCE_ID = 2;
2483035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_VERSION = 3;
2484035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_DIRTY = 4;
2485035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        private static final int COLUMN_DATA_ID = 5;
248667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_RES_PACKAGE = 6;
248767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_MIMETYPE = 7;
248867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_DATA1 = 8;
248967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_CONTACT_ID = 23;
249067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_IS_PRIMARY = 24;
249167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_DATA_VERSION = 25;
249267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        private static final int COLUMN_GROUP_SOURCE_ID = 26;
24937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
24947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public ContactsEntityIterator(ContactsProvider2 provider, String contactsIdString, Uri uri,
24957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                String selection, String[] selectionArgs, String sortOrder) {
24967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mIsClosed = false;
24977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
24987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final String updatedSortOrder = (sortOrder == null)
24995ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    ? RawContacts.Data.RAW_CONTACT_ID
25005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    : (RawContacts.Data.RAW_CONTACT_ID + "," + sortOrder);
25017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase();
25037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
2504226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setTables(Tables.CONTACT_ENTITIES);
25057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (contactsIdString != null) {
25065ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                qb.appendWhere(Data.RAW_CONTACT_ID + "=" + contactsIdString);
25077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
25086cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
25096cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
2510035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            if (!TextUtils.isEmpty(accountName)) {
25116cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
2512035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                        + DatabaseUtils.sqlEscapeString(accountName) + " AND "
25136cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                        + RawContacts.ACCOUNT_TYPE + "="
2514035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                        + DatabaseUtils.sqlEscapeString(accountType));
2515035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana            }
25167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs,
25177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    null, null, updatedSortOrder);
25187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor.moveToFirst();
25197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
25207e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public void close() {
25227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
25237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("closing when already closed");
25247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
25257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mIsClosed = true;
25267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            mEntityCursor.close();
25277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
25287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public boolean hasNext() throws RemoteException {
25307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
25317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("calling hasNext() when the iterator is closed");
25327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
25337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return !mEntityCursor.isAfterLast();
25357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
25367e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25377e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public Entity next() throws RemoteException {
25387e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (mIsClosed) {
25397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("calling next() when the iterator is closed");
25407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
25417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            if (!hasNext()) {
25427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new IllegalStateException("you may only call next() if hasNext() is true");
25437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
25447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            final SQLiteCursor c = (SQLiteCursor) mEntityCursor;
25467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25475ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            final long rawContactId = c.getLong(COLUMN_CONTACT_ID);
25487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            // we expect the cursor is already at the row we need to read from
25507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            ContentValues contactValues = new ContentValues();
25516cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME));
25526cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE));
25535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            contactValues.put(RawContacts._ID, rawContactId);
25546cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.DIRTY, c.getLong(COLUMN_DIRTY));
25556cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.VERSION, c.getLong(COLUMN_VERSION));
25566cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            contactValues.put(RawContacts.SOURCE_ID, c.getString(COLUMN_SOURCE_ID));
25577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            Entity contact = new Entity(contactValues);
25587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            // read data rows until the contact id changes
25607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            do {
25615ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                if (rawContactId != c.getLong(COLUMN_CONTACT_ID)) {
25627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    break;
25637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
25647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                // add the data to to the contact
25657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                ContentValues dataValues = new ContentValues();
25666cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                dataValues.put(RawContacts.Data._ID, c.getString(COLUMN_DATA_ID));
25676cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                dataValues.put(RawContacts.Data.RES_PACKAGE, c.getString(COLUMN_RES_PACKAGE));
25686cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                dataValues.put(RawContacts.Data.MIMETYPE, c.getString(COLUMN_MIMETYPE));
25696cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                dataValues.put(RawContacts.Data.IS_PRIMARY, c.getString(COLUMN_IS_PRIMARY));
25706cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                dataValues.put(RawContacts.Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION));
25719261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (!c.isNull(COLUMN_GROUP_SOURCE_ID)) {
25729261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    dataValues.put(GroupMembership.GROUP_SOURCE_ID,
25739261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            c.getString(COLUMN_GROUP_SOURCE_ID));
25749261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
25756cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                dataValues.put(RawContacts.Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION));
25767e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                for (int i = 0; i < 10; i++) {
25777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    final int columnIndex = i + COLUMN_DATA1;
25787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    String key = DATA_KEYS[i];
25797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    if (c.isNull(columnIndex)) {
25807e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        // don't put anything
25817e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isLong(columnIndex)) {
25827e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getLong(columnIndex));
25837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isFloat(columnIndex)) {
25847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getFloat(columnIndex));
25857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isString(columnIndex)) {
25867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getString(columnIndex));
25877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    } else if (c.isBlob(columnIndex)) {
25887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        dataValues.put(key, c.getBlob(columnIndex));
25897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    }
25907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
25917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                contact.addSubValue(Data.CONTENT_URI, dataValues);
25927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            } while (mEntityCursor.moveToNext());
25937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return contact;
25957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
25967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
25977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
2598226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    /**
2599226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     * An implementation of EntityIterator that joins the contacts and data tables
2600226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     * and consumes all the data rows for a contact in order to build the Entity for a contact.
2601226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana     */
2602226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    private static class GroupsEntityIterator implements EntityIterator {
2603226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private final Cursor mEntityCursor;
2604226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private volatile boolean mIsClosed;
2605226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2606226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final String[] PROJECTION = new String[]{
2607226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups._ID,
2608226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.ACCOUNT_NAME,
2609226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.ACCOUNT_TYPE,
2610226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.SOURCE_ID,
2611226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.DIRTY,
2612226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.VERSION,
2613226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.RES_PACKAGE,
2614226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.TITLE,
2615226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.TITLE_RES,
2616226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                Groups.GROUP_VISIBLE};
2617226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2618226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ID = 0;
2619226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ACCOUNT_NAME = 1;
2620226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_ACCOUNT_TYPE = 2;
2621226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_SOURCE_ID = 3;
2622226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_DIRTY = 4;
2623226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_VERSION = 5;
2624226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_RES_PACKAGE = 6;
2625226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_TITLE = 7;
2626226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_TITLE_RES = 8;
2627226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        private static final int COLUMN_GROUP_VISIBLE = 9;
2628226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2629226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public GroupsEntityIterator(ContactsProvider2 provider, String groupIdString, Uri uri,
2630226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                String selection, String[] selectionArgs, String sortOrder) {
2631226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mIsClosed = false;
2632226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2633226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String updatedSortOrder = (sortOrder == null)
2634226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    ? Groups._ID
2635226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    : (Groups._ID + "," + sortOrder);
2636226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2637226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase();
2638226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
2639226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setTables(Tables.GROUPS_JOIN_PACKAGES);
2640226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            qb.setProjectionMap(sGroupsProjectionMap);
2641226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (groupIdString != null) {
2642226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                qb.appendWhere(Groups._ID + "=" + groupIdString);
2643226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2644226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String accountName = uri.getQueryParameter(Groups.ACCOUNT_NAME);
2645226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final String accountType = uri.getQueryParameter(Groups.ACCOUNT_TYPE);
2646226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (!TextUtils.isEmpty(accountName)) {
2647226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                qb.appendWhere(Groups.ACCOUNT_NAME + "="
2648226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + DatabaseUtils.sqlEscapeString(accountName) + " AND "
2649226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + Groups.ACCOUNT_TYPE + "="
2650226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        + DatabaseUtils.sqlEscapeString(accountType));
2651226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2652226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs,
2653226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    null, null, updatedSortOrder);
2654226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.moveToFirst();
2655226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
2656226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2657226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public void close() {
2658226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
2659226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("closing when already closed");
2660226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2661226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mIsClosed = true;
2662226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.close();
2663226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
2664226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2665226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public boolean hasNext() throws RemoteException {
2666226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
2667226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("calling hasNext() when the iterator is closed");
2668226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2669226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2670226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            return !mEntityCursor.isAfterLast();
2671226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
2672226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2673226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        public Entity next() throws RemoteException {
2674226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (mIsClosed) {
2675226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("calling next() when the iterator is closed");
2676226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2677226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            if (!hasNext()) {
2678226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                throw new IllegalStateException("you may only call next() if hasNext() is true");
2679226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            }
2680226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2681226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final SQLiteCursor c = (SQLiteCursor) mEntityCursor;
2682226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2683226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            final long groupId = c.getLong(COLUMN_ID);
2684226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2685226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            // we expect the cursor is already at the row we need to read from
2686226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            ContentValues groupValues = new ContentValues();
2687226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME));
2688226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE));
2689226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups._ID, groupId);
2690226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.DIRTY, c.getLong(COLUMN_DIRTY));
2691226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.VERSION, c.getLong(COLUMN_VERSION));
2692226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.SOURCE_ID, c.getString(COLUMN_SOURCE_ID));
2693226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.RES_PACKAGE, c.getString(COLUMN_RES_PACKAGE));
2694226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.TITLE, c.getString(COLUMN_TITLE));
2695226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.TITLE_RES, c.getString(COLUMN_TITLE_RES));
2696226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            groupValues.put(Groups.GROUP_VISIBLE, c.getLong(COLUMN_GROUP_VISIBLE));
2697226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            Entity group = new Entity(groupValues);
2698226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2699226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            mEntityCursor.moveToNext();
2700226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2701226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            return group;
2702226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana        }
2703226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana    }
2704226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2705a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    @Override
27067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
27077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            String sortOrder) {
27087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        final int match = sUriMatcher.match(uri);
27097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        switch (match) {
27105ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS:
27115ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID:
27127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                String contactsIdString = null;
27135ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                if (match == RAW_CONTACTS_ID) {
27147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                    contactsIdString = uri.getPathSegments().get(1);
27157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                }
27167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
27177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                return new ContactsEntityIterator(this, contactsIdString,
27187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                        uri, selection, selectionArgs, sortOrder);
2719226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            case GROUPS:
2720226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana            case GROUPS_ID:
2721226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                String idString = null;
2722226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                if (match == GROUPS_ID) {
2723226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                    idString = uri.getPathSegments().get(1);
2724226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                }
2725226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana
2726226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                return new GroupsEntityIterator(this, idString,
2727226c3dc6e93ca76a84c99100caa31045cba06cf6Fred Quintana                        uri, selection, selectionArgs, sortOrder);
27287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            default:
27297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                throw new UnsupportedOperationException("Unknown uri: " + uri);
27307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
27317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
27327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
27334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
27344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public String getType(Uri uri) {
2735a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
27364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
2737d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: return Contacts.CONTENT_TYPE;
2738d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: return Contacts.CONTENT_ITEM_TYPE;
27395ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: return RawContacts.CONTENT_TYPE;
27405ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: return RawContacts.CONTENT_ITEM_TYPE;
2741508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            case DATA_ID:
27426bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
2743508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey                long dataId = ContentUris.parseId(uri);
2744b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                return mOpenHelper.getDataMimeType(dataId);
274531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_EXCEPTIONS: return AggregationExceptions.CONTENT_TYPE;
274631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_EXCEPTION_ID: return AggregationExceptions.CONTENT_ITEM_TYPE;
2747d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case AGGREGATION_SUGGESTIONS: return Contacts.CONTENT_TYPE;
2748c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS:
2749c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SUGGEST_MIME_TYPE;
2750c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT:
2751c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SHORTCUT_MIME_TYPE;
27524f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
2753a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        throw new UnsupportedOperationException("Unknown uri: " + uri);
27544f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
27557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
2756b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    @Override
27577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
27587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            throws OperationApplicationException {
27597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
27607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
27617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        db.beginTransaction();
27627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        try {
27637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            ContentProviderResult[] results = super.applyBatch(operations);
27647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            db.setTransactionSuccessful();
27657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return results;
27667e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        } finally {
27677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            db.endTransaction();
27687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
27697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
2770c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
27715ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private void setDisplayName(long rawContactId, String displayName) {
27723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (displayName != null) {
27733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mContactDisplayNameUpdate.bindString(1, displayName);
27743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        } else {
27753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mContactDisplayNameUpdate.bindNull(1);
27763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
27775ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mContactDisplayNameUpdate.bindLong(2, rawContactId);
27783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        mContactDisplayNameUpdate.execute();
27793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
27803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
2781c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
2782c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to primary, and resets all data records of
2783c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * the same mimetype and under the same contact to not be primary.
2784c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
2785c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
2786c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
2787c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private void setIsPrimary(long dataId) {
2788c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.bindLong(1, dataId);
2789c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.bindLong(2, dataId);
2790c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.bindLong(3, dataId);
2791c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetPrimaryStatement.execute();
2792c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
2793c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
2794c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    /*
2795c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * Sets the given dataId record in the "data" table to "super primary", and resets all data
2796c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * records of the same mimetype and under the same aggregate to not be "super primary".
2797c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     *
2798c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     * @param dataId the id of the data record to be set to primary.
2799c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar     */
2800c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    private void setIsSuperPrimary(long dataId) {
2801c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.bindLong(1, dataId);
2802c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.bindLong(2, dataId);
2803c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.bindLong(3, dataId);
2804c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar        mSetSuperPrimaryStatement.execute();
2805619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2806619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // Find the parent aggregate and package for this new primary
2807619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
2808619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2809619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        long aggId = -1;
2810619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        boolean isRestricted = false;
2811619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        String mimeType = null;
2812619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2813619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        Cursor cursor = null;
2814619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        try {
2815d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            cursor = db.query(DataRawContactsQuery.TABLE, DataRawContactsQuery.PROJECTION,
281667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                    DataColumns.CONCRETE_ID + "=" + dataId, null, null, null, null);
2817619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            if (cursor.moveToFirst()) {
2818d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                aggId = cursor.getLong(DataRawContactsQuery.CONTACT_ID);
2819d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                isRestricted = (cursor.getInt(DataRawContactsQuery.IS_RESTRICTED) == 1);
2820d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                mimeType = cursor.getString(DataRawContactsQuery.MIMETYPE);
2821619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            }
2822619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        } finally {
2823619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            if (cursor != null) {
2824619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                cursor.close();
2825619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            }
2826619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
2827619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2828619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // Bypass aggregate update if no parent found, or if we don't keep track
2829619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // of super-primary for this mimetype.
2830d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        if (aggId == -1) {
2831d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov            return;
2832d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        }
2833619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2834619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        boolean isPhone = CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mimeType);
2835619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        boolean isEmail = CommonDataKinds.Email.CONTENT_ITEM_TYPE.equals(mimeType);
2836619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2837619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // Record this value as the new primary for the parent aggregate
2838619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        final ContentValues values = new ContentValues();
2839619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        if (isPhone) {
2840d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            values.put(ContactsColumns.OPTIMAL_PRIMARY_PHONE_ID, dataId);
2841d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            values.put(ContactsColumns.OPTIMAL_PRIMARY_PHONE_IS_RESTRICTED, isRestricted);
2842619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        } else if (isEmail) {
2843d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            values.put(ContactsColumns.OPTIMAL_PRIMARY_EMAIL_ID, dataId);
2844d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            values.put(ContactsColumns.OPTIMAL_PRIMARY_EMAIL_IS_RESTRICTED, isRestricted);
2845619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
2846619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2847619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // If this data is unrestricted, then also set as fallback
2848619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        if (!isRestricted && isPhone) {
2849d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            values.put(ContactsColumns.FALLBACK_PRIMARY_PHONE_ID, dataId);
2850619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        } else if (!isRestricted && isEmail) {
2851d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            values.put(ContactsColumns.FALLBACK_PRIMARY_EMAIL_ID, dataId);
2852619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
2853619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
2854d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        // Push update into contacts table, if needed
2855619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        if (values.size() > 0) {
2856d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            db.update(Tables.CONTACTS, values, Contacts._ID + "=" + aggId, null);
2857619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
2858c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar    }
2859ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
2860d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private String buildContactLookupWhereClause(String filterParam) {
2861ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        StringBuilder filter = new StringBuilder();
2862d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        filter.append(Tables.CONTACTS);
2863ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        filter.append(".");
2864d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        filter.append(Contacts._ID);
2865ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        filter.append(" IN (SELECT ");
2866d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        filter.append(RawContacts.CONTACT_ID);
2867ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        filter.append(" FROM ");
28685ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        filter.append(Tables.RAW_CONTACTS);
2869ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        filter.append(" WHERE ");
28706cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        filter.append(RawContacts._ID);
2871445ca81effbb0d61c7bc0033acf2d3dfd228fd4eDmitri Plotnikov        filter.append(" IN ");
2872c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        appendRawContactsByFilterAsNestedQuery(filter, filterParam, null);
2873445ca81effbb0d61c7bc0033acf2d3dfd228fd4eDmitri Plotnikov        filter.append(")");
2874445ca81effbb0d61c7bc0033acf2d3dfd228fd4eDmitri Plotnikov        return filter.toString();
2875445ca81effbb0d61c7bc0033acf2d3dfd228fd4eDmitri Plotnikov    }
2876445ca81effbb0d61c7bc0033acf2d3dfd228fd4eDmitri Plotnikov
28775ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public String getRawContactsByFilterAsNestedQuery(String filterParam) {
2878c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        StringBuilder sb = new StringBuilder();
2879c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        appendRawContactsByFilterAsNestedQuery(sb, filterParam, null);
2880c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        return sb.toString();
2881c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
2882c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2883a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    public void appendRawContactsByFilterAsNestedQuery(StringBuilder sb, String filterParam,
2884c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            String limit) {
2885c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append("(SELECT DISTINCT raw_contact_id FROM name_lookup WHERE normalized_name GLOB '");
2886c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append(NameNormalizer.normalize(filterParam));
2887c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append("*'");
2888c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limit != null) {
2889c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            sb.append(" LIMIT ").append(limit);
2890c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
2891c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        sb.append(")");
2892ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    }
2893ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
2894b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    private String[] appendGroupArg(String[] selectionArgs, String arg) {
2895b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        if (selectionArgs == null) {
2896b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return new String[] {arg};
2897b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        } else {
2898b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            int newLength = selectionArgs.length + 1;
2899b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            String[] newSelectionArgs = new String[newLength];
2900b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            System.arraycopy(selectionArgs, 0, newSelectionArgs, 0, selectionArgs.length);
2901b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            newSelectionArgs[newLength - 1] = arg;
2902b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return newSelectionArgs;
2903b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        }
2904b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    }
29054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton}
2906