ContactsProvider2.java revision 70b5ee6864cb3368d24a9e876fb93008997b12df
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.AggregatesColumns; 2128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.AggregationExceptionColumns; 2228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.Clauses; 2328f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.ContactsColumns; 2428f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.DataColumns; 2528f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.GroupsColumns; 2628f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.MimetypesColumns; 27e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikovimport com.android.providers.contacts.OpenHelper.PhoneColumns; 2867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport com.android.providers.contacts.OpenHelper.PackagesColumns; 2928f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.PhoneLookupColumns; 3028f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.Tables; 31e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikovimport com.google.android.collect.Lists; 32e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov 33b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account; 344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.content.ContentProvider; 3567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentProviderOperation; 3667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentProviderResult; 3735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris; 3867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues; 3967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context; 4035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.Entity; 4167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.EntityIterator; 427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport android.content.OperationApplicationException; 4367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher; 4467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.pm.PackageManager; 454f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor; 46ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils; 47b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.database.sqlite.SQLiteCursor; 484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase; 494f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder; 50c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millarimport android.database.sqlite.SQLiteStatement; 514f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri; 52619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.os.Binder; 53b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException; 54508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns; 55de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract; 566bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikovimport android.provider.Contacts.ContactMethods; 57de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Aggregates; 58b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions; 59de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds; 60de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Contacts; 61de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Data; 62ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.Groups; 631f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkeyimport android.provider.ContactsContract.Presence; 646bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikovimport android.provider.ContactsContract.Aggregates.AggregationSuggestions; 653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.BaseTypes; 66ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Email; 67ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.GroupMembership; 683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im; 693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname; 703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization; 71de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds.Phone; 724097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 7367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 74a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils; 75a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils; 7600d71133c63c882fb41729ddc3a52f66fb155374Evan Millarimport 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 97d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final String STREQUENT_ORDER_BY = Aggregates.STARRED + " DESC, " 98d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar + Aggregates.TIMES_CONTACTED + " DESC, " 99d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar + Aggregates.DISPLAY_NAME + " ASC"; 100d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final String STREQUENT_LIMIT = 101d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar "(SELECT COUNT(1) FROM " + Tables.AGGREGATES + " WHERE " 102d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar + Aggregates.STARRED + "=1) + 25"; 103d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 1046bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int AGGREGATES = 1000; 1056bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int AGGREGATES_ID = 1001; 1066bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int AGGREGATES_DATA = 1002; 1071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final int AGGREGATES_SUMMARY = 1003; 1081f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final int AGGREGATES_SUMMARY_ID = 1004; 109ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int AGGREGATES_SUMMARY_FILTER = 1005; 110d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final int AGGREGATES_SUMMARY_STREQUENT = 1006; 111d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final int AGGREGATES_SUMMARY_STREQUENT_FILTER = 1007; 112b67163a1088f09c59f324350662eb18772fac6b6Evan Millar private static final int AGGREGATES_SUMMARY_GROUP = 1008; 1134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1146bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int CONTACTS = 2002; 1156bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int CONTACTS_ID = 2003; 1166bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int CONTACTS_DATA = 2004; 11728ab0f857caa92402878244d9c5ea2a59e070935Jeff Sharkey private static final int CONTACTS_FILTER_EMAIL = 2005; 1184f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1196bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA = 3000; 1206bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA_ID = 3001; 121ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES = 3002; 122ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES_FILTER = 3003; 123ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int POSTALS = 3004; 124a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1256bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int PHONE_LOOKUP = 4000; 1266bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 127b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTIONS = 6000; 128b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTION_ID = 6001; 129b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 1301f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final int PRESENCE = 7000; 1311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final int PRESENCE_ID = 7001; 1321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 13331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int AGGREGATION_SUGGESTIONS = 8000; 13431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 135ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS = 10000; 136ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_ID = 10001; 137ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_SUMMARY = 10003; 138ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 13935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private static final int SYNCSTATE = 11000; 14035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 14167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private interface ContactsQuery { 14267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String TABLE = Tables.CONTACTS; 1439261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 14467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String[] PROJECTION = new String[] { 145ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.CONCRETE_ID, 14667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Contacts.ACCOUNT_NAME, 14767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Contacts.ACCOUNT_TYPE, 148ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 149ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 15067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int CONTACT_ID = 0; 15167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int ACCOUNT_NAME = 1; 15267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int ACCOUNT_TYPE = 2; 15367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 15467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 15567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private interface DataContactsQuery { 156c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov public static final String TABLE = Tables.DATA_JOIN_MIMETYPE_CONTACTS; 15767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 15867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String[] PROJECTION = new String[] { 1593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov ContactsColumns.CONCRETE_ID, 1603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataColumns.CONCRETE_ID, 1613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Contacts.AGGREGATE_ID, 1623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Contacts.IS_RESTRICTED, 1633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.MIMETYPE, 164ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 165ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 16667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int CONTACT_ID = 0; 16767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int DATA_ID = 1; 16867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int AGGREGATE_ID = 2; 16967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int IS_RESTRICTED = 3; 17067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int MIMETYPE = 4; 17167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 17267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 17367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private interface DataAggregatesQuery { 17467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String TABLE = Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES; 17567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 17667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String[] PROJECTION = new String[] { 177ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.CONCRETE_ID, 1783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataColumns.CONCRETE_ID, 1793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov AggregatesColumns.CONCRETE_ID, 1803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov MimetypesColumns.CONCRETE_ID, 1813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Phone.NUMBER, 1823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Email.DATA, 1833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID, 1843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID, 1853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID, 1863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID, 187ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 188ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 18967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int CONTACT_ID = 0; 19067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int DATA_ID = 1; 19167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int AGGREGATE_ID = 2; 19267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int MIMETYPE_ID = 3; 19367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int PHONE_NUMBER = 4; 19467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int EMAIL_DATA = 5; 19567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int OPTIMAL_PHONE_ID = 6; 19667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int FALLBACK_PHONE_ID = 7; 19767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int OPTIMAL_EMAIL_ID = 8; 19867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int FALLBACK_EMAIL_ID = 9; 19980c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 200ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private interface DisplayNameQuery { 20367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String TABLE = Tables.DATA_JOIN_MIMETYPES; 2043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 2053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final String[] COLUMNS = new String[] { 2063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov MimetypesColumns.MIMETYPE, 2073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.IS_PRIMARY, 2083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.DATA2, 2093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov StructuredName.DISPLAY_NAME, 2103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov }; 2113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 2123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int MIMETYPE = 0; 2133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int IS_PRIMARY = 1; 2143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DATA2 = 2; 2153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DISPLAY_NAME = 3; 2163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 2173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 2183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private interface DataQuery { 21967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String TABLE = Tables.DATA_JOIN_MIMETYPES; 2203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 2213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final String[] COLUMNS = new String[] { 2223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataColumns.CONCRETE_ID, 2233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov MimetypesColumns.MIMETYPE, 2243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.CONTACT_ID, 2253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.IS_PRIMARY, 2263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.DATA1, 2273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.DATA2, 2283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.DATA3, 2293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.DATA4, 2303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.DATA5, 2313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.DATA6, 2323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.DATA7, 2333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.DATA8, 2343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.DATA9, 2353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.DATA10, 23667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Data.DATA11, 23767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Data.DATA12, 23867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Data.DATA13, 23967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Data.DATA14, 24067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Data.DATA15, 2413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov }; 2423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 2433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int ID = 0; 2443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int MIMETYPE = 1; 2453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int CONTACT_ID = 2; 2463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int IS_PRIMARY = 3; 2473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DATA1 = 4; 2483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DATA2 = 5; 2493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DATA3 = 6; 2503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DATA4 = 7; 2513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DATA5 = 8; 2523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DATA6 = 9; 2533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DATA7 = 10; 2543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DATA8 = 11; 2553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DATA9 = 12; 2563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public static final int DATA10 = 13; 25767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int DATA11 = 14; 25867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int DATA12 = 15; 25967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int DATA13 = 16; 26067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int DATA14 = 17; 26167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final int DATA15 = 18; 2623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 2633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 26420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private interface DataIdQuery { 26520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String[] COLUMNS = { Data._ID }; 26620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 26720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int _ID = 0; 26820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 26920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov // Higher number represents higher priority in choosing what data to use for the display name 2713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final int DISPLAY_NAME_PRIORITY_EMAIL = 1; 2723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final int DISPLAY_NAME_PRIORITY_PHONE = 2; 2733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final int DISPLAY_NAME_PRIORITY_ORGANIZATION = 3; 2743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final int DISPLAY_NAME_PRIORITY_STRUCTURED_NAME = 4; 2753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 2763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final HashMap<String, Integer> sDisplayNamePriorities; 2773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov static { 2783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov sDisplayNamePriorities = new HashMap<String, Integer>(); 2793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov sDisplayNamePriorities.put(StructuredName.CONTENT_ITEM_TYPE, 2803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DISPLAY_NAME_PRIORITY_STRUCTURED_NAME); 2813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov sDisplayNamePriorities.put(Organization.CONTENT_ITEM_TYPE, 2823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DISPLAY_NAME_PRIORITY_ORGANIZATION); 2833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov sDisplayNamePriorities.put(Phone.CONTENT_ITEM_TYPE, 2843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DISPLAY_NAME_PRIORITY_PHONE); 2853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov sDisplayNamePriorities.put(Email.CONTENT_ITEM_TYPE, 2863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DISPLAY_NAME_PRIORITY_EMAIL); 2873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 28831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 2896bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** Contains just the contacts columns */ 2906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final HashMap<String, String> sAggregatesProjectionMap; 29100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar /** Contains the aggregate columns along with primary phone */ 2921f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final HashMap<String, String> sAggregatesSummaryProjectionMap; 293de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar /** Contains the data, contacts, and aggregate columns, for joined tables. */ 294de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar private static final HashMap<String, String> sDataContactsAggregateProjectionMap; 2959261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data, contacts, group sourceid and aggregate columns, for joined tables. */ 2969261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana private static final HashMap<String, String> sDataContactsGroupsAggregateProjectionMap; 297a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** Contains just the contacts columns */ 2984f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton private static final HashMap<String, String> sContactsProjectionMap; 299a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** Contains just the data columns */ 3009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana private static final HashMap<String, String> sDataGroupsProjectionMap; 3019261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data and contacts columns, for joined tables */ 3029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana private static final HashMap<String, String> sDataContactsGroupsProjectionMap; 303a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** Contains the data and contacts columns, for joined tables */ 304a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton private static final HashMap<String, String> sDataContactsProjectionMap; 305ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains the just the {@link Groups} columns */ 306ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final HashMap<String, String> sGroupsProjectionMap; 307ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains {@link Groups} columns along with summary details */ 308ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final HashMap<String, String> sGroupsSummaryProjectionMap; 309b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov /** Contains the just the agg_exceptions columns */ 310b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final HashMap<String, String> sAggregationExceptionsProjectionMap; 3117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 312c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns the contact id associated with a data record. */ 313c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedContactIdSelect; 314c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns the mimetype id associated with a data record. */ 315c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedMimetypeSelect; 316c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns the aggregate id associated with a contact record. */ 317c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedAggregateIdSelect; 318c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns a list of contact ids associated with an aggregate record. */ 319c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedContactIdListSelect; 320c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql where statement used to match all the data records that need to be updated when a new 321c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * "primary" is selected.*/ 322c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sSetPrimaryWhere; 323c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql where statement used to match all the data records that need to be updated when a new 324c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * "super primary" is selected.*/ 325c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sSetSuperPrimaryWhere; 326b67163a1088f09c59f324350662eb18772fac6b6Evan Millar /** Sql where statement for filtering on groups. */ 327b67163a1088f09c59f324350662eb18772fac6b6Evan Millar private static final String sAggregatesInGroupSelect; 328c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Precompiled sql statement for setting a data record to the primary. */ 329c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private SQLiteStatement mSetPrimaryStatement; 3303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** Precompiled sql statement for setting a data record to the super primary. */ 331c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private SQLiteStatement mSetSuperPrimaryStatement; 3323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** Precompiled sql statement for incrementing times contacted for an aggregate */ 333f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private SQLiteStatement mLastTimeContactedUpdate; 3343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** Precompiled sql statement for updating a contact display name */ 3353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private SQLiteStatement mContactDisplayNameUpdate; 336a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 3371f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final String GTALK_PROTOCOL_STRING = ContactMethods 3381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey .encodePredefinedImProtocol(ContactMethods.PROTOCOL_GOOGLE_TALK); 3391f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3404f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 3414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 342a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 3436bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates", AGGREGATES); 3446bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates/#", AGGREGATES_ID); 3456bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates/#/data", AGGREGATES_DATA); 3461f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary", AGGREGATES_SUMMARY); 3471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/#", AGGREGATES_SUMMARY_ID); 348ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/filter/*", 349ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar AGGREGATES_SUMMARY_FILTER); 350d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/strequent/", 351d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar AGGREGATES_SUMMARY_STREQUENT); 352d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/strequent/filter/*", 353d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar AGGREGATES_SUMMARY_STREQUENT_FILTER); 354b67163a1088f09c59f324350662eb18772fac6b6Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/group/*", 355b67163a1088f09c59f324350662eb18772fac6b6Evan Millar AGGREGATES_SUMMARY_GROUP); 35631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates/#/suggestions", 35731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 3584f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 3594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 360a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_DATA); 361b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter_email/*", 362b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov CONTACTS_FILTER_EMAIL); 363b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 3644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 3654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 366ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 367ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 368ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 3691f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 370ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 371ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 372ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 373ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 37435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 37535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 376a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 377b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 378b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 379b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 380b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 3814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 382bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "presence", PRESENCE); 383bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "presence/#", PRESENCE_ID); 3841f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 385fec4e13316f2731d84394e5fa2f93af3febdc20cEvan Millar HashMap<String, String> columns; 3864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 3876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov // Aggregates projection map 3886bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns = new HashMap<String, String>(); 38900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar columns.put(Aggregates._ID, "aggregates._id AS _id"); 39067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Aggregates.DISPLAY_NAME, AggregatesColumns.CONCRETE_DISPLAY_NAME + " AS " 39167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + Aggregates.DISPLAY_NAME); 39267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Aggregates.LAST_TIME_CONTACTED, AggregatesColumns.CONCRETE_LAST_TIME_CONTACTED 39367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + " AS " + Aggregates.LAST_TIME_CONTACTED); 39467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Aggregates.TIMES_CONTACTED, AggregatesColumns.CONCRETE_TIMES_CONTACTED + " AS " 39567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + Aggregates.TIMES_CONTACTED); 39667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Aggregates.STARRED, AggregatesColumns.CONCRETE_STARRED + " AS " 39767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + Aggregates.STARRED); 398ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Aggregates.IN_VISIBLE_GROUP, Aggregates.IN_VISIBLE_GROUP); 399ae6ca1f34cf5458d79ec803411d4308879a91e92Evan Millar columns.put(Aggregates.PHOTO_ID, Aggregates.PHOTO_ID); 400de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar columns.put(Aggregates.PRIMARY_PHONE_ID, Aggregates.PRIMARY_PHONE_ID); 401c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar columns.put(Aggregates.PRIMARY_EMAIL_ID, Aggregates.PRIMARY_EMAIL_ID); 40267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Aggregates.CUSTOM_RINGTONE, AggregatesColumns.CONCRETE_CUSTOM_RINGTONE + " AS " 40367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + Aggregates.CUSTOM_RINGTONE); 40467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Aggregates.SEND_TO_VOICEMAIL, AggregatesColumns.CONCRETE_SEND_TO_VOICEMAIL 40567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + " AS " + Aggregates.SEND_TO_VOICEMAIL); 406619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID, 407619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID); 408619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID, 409619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID); 4106bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov sAggregatesProjectionMap = columns; 4116bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 4121f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey columns = new HashMap<String, String>(); 4131f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey columns.putAll(sAggregatesProjectionMap); 414c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov 415c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov // Aggregates primaries projection map. The overall presence status is 416c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov // the most-present value, as indicated by the largest value. 417c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov columns.put(Aggregates.PRESENCE_STATUS, "MAX(" + Presence.PRESENCE_STATUS + ")"); 418c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov columns.put(Aggregates.PRIMARY_PHONE_TYPE, CommonDataKinds.Phone.TYPE); 419c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov columns.put(Aggregates.PRIMARY_PHONE_LABEL, CommonDataKinds.Phone.LABEL); 420c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov columns.put(Aggregates.PRIMARY_PHONE_NUMBER, CommonDataKinds.Phone.NUMBER); 4211f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey sAggregatesSummaryProjectionMap = columns; 42200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 4234f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts projection map 4244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns = new HashMap<String, String>(); 4254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns.put(Contacts._ID, "contacts._id AS _id"); 4266bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns.put(Contacts.AGGREGATE_ID, Contacts.AGGREGATE_ID); 4279261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Contacts.ACCOUNT_NAME, 4289261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana OpenHelper.ContactsColumns.CONCRETE_ACCOUNT_NAME + " as " + Contacts.ACCOUNT_NAME); 4299261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Contacts.ACCOUNT_TYPE, 4309261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana OpenHelper.ContactsColumns.CONCRETE_ACCOUNT_TYPE + " as " + Contacts.ACCOUNT_TYPE); 4319261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Contacts.SOURCE_ID, 4329261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana OpenHelper.ContactsColumns.CONCRETE_SOURCE_ID + " as " + Contacts.SOURCE_ID); 4339261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Contacts.VERSION, 4349261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana OpenHelper.ContactsColumns.CONCRETE_VERSION + " as " + Contacts.VERSION); 4359261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Contacts.DIRTY, 4369261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana OpenHelper.ContactsColumns.CONCRETE_DIRTY + " as " + Contacts.DIRTY); 4374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton sContactsProjectionMap = columns; 4384f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 4394f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Data projection map 4404f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns = new HashMap<String, String>(); 4414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns.put(Data._ID, "data._id AS _id"); 4424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns.put(Data.CONTACT_ID, Data.CONTACT_ID); 44367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Data.RES_PACKAGE, PackagesColumns.PACKAGE + " AS " + Data.RES_PACKAGE); 444508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey columns.put(Data.MIMETYPE, Data.MIMETYPE); 445c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar columns.put(Data.IS_PRIMARY, Data.IS_PRIMARY); 446c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar columns.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY); 447f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana columns.put(Data.DATA_VERSION, Data.DATA_VERSION); 4487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA1, "data.data1 as data1"); 4497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA2, "data.data2 as data2"); 4507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA3, "data.data3 as data3"); 4517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA4, "data.data4 as data4"); 4527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA5, "data.data5 as data5"); 4537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA6, "data.data6 as data6"); 4547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA7, "data.data7 as data7"); 4557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA8, "data.data8 as data8"); 4567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA9, "data.data9 as data9"); 4577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA10, "data.data10 as data10"); 45867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Data.DATA11, "data.data11 as data11"); 45967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Data.DATA12, "data.data12 as data12"); 46067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Data.DATA13, "data.data13 as data13"); 46167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Data.DATA14, "data.data14 as data14"); 46267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Data.DATA15, "data.data15 as data15"); 46367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(GroupMembership.GROUP_SOURCE_ID, GroupsColumns.CONCRETE_SOURCE_ID + " AS " 46467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + GroupMembership.GROUP_SOURCE_ID); 46520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 46620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov // TODO: remove this projection 467d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Mappings used for backwards compatibility. 468d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar columns.put("number", Phone.NUMBER); 4699261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana sDataGroupsProjectionMap = columns; 470a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 4719261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana // Data, groups and contacts projection map for joins. _id comes from the data table 472a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton columns = new HashMap<String, String>(); 473a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton columns.putAll(sContactsProjectionMap); 4749261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.putAll(sDataGroupsProjectionMap); // _id will be replaced with the one from data 475ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Data.CONTACT_ID, DataColumns.CONCRETE_CONTACT_ID); 4769261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana sDataContactsGroupsProjectionMap = columns; 4779261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 4789261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana // Data and contacts projection map for joins. _id comes from the data table 4799261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns = new HashMap<String, String>(); 4809261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.putAll(sDataContactsGroupsProjectionMap); 4819261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.remove(GroupMembership.GROUP_SOURCE_ID); 482a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton sDataContactsProjectionMap = columns; 4837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 484de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar // Data and contacts projection map for joins. _id comes from the data table 485de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar columns = new HashMap<String, String>(); 486de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar columns.putAll(sAggregatesProjectionMap); 4877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.putAll(sContactsProjectionMap); // 4889261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.putAll(sDataGroupsProjectionMap); // _id will be replaced with the one from data 489ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Data.CONTACT_ID, DataColumns.CONCRETE_CONTACT_ID); 4909261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana sDataContactsGroupsAggregateProjectionMap = columns; 4919261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 4929261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana // Data and contacts projection map for joins. _id comes from the data table 4939261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns = new HashMap<String, String>(); 4949261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.putAll(sDataContactsGroupsAggregateProjectionMap); 4959261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.remove(GroupMembership.GROUP_SOURCE_ID); 496de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar sDataContactsAggregateProjectionMap = columns; 497c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 498ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Groups projection map 499ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns = new HashMap<String, String>(); 500ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups._ID, "groups._id AS _id"); 501035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana columns.put(Groups.ACCOUNT_NAME, Groups.ACCOUNT_NAME); 502035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana columns.put(Groups.ACCOUNT_TYPE, Groups.ACCOUNT_TYPE); 5039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Groups.SOURCE_ID, Groups.SOURCE_ID); 5049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Groups.DIRTY, Groups.DIRTY); 5059261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Groups.VERSION, Groups.VERSION); 50667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Groups.RES_PACKAGE, PackagesColumns.PACKAGE + " AS " + Groups.RES_PACKAGE); 507ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.TITLE, Groups.TITLE); 50867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey columns.put(Groups.TITLE_RES, Groups.TITLE_RES); 509ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.GROUP_VISIBLE, Groups.GROUP_VISIBLE); 510ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey sGroupsProjectionMap = columns; 511ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 512ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Contacts and groups projection map 513ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns = new HashMap<String, String>(); 514ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.putAll(sGroupsProjectionMap); 515ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 516ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.SUMMARY_COUNT, "(SELECT COUNT(DISTINCT " + AggregatesColumns.CONCRETE_ID 517ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + ") FROM " + Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES + " WHERE " 518ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP 519ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + ") AS " + Groups.SUMMARY_COUNT); 520ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 521ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.SUMMARY_WITH_PHONES, "(SELECT COUNT(DISTINCT " 522ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + AggregatesColumns.CONCRETE_ID + ") FROM " 523ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES + " WHERE " 524ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP 525ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + " AND " + Clauses.HAS_PRIMARY_PHONE + ") AS " + Groups.SUMMARY_WITH_PHONES); 526ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 527ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey sGroupsSummaryProjectionMap = columns; 528ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 529b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov // Aggregate exception projection map 530b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov columns = new HashMap<String, String>(); 531b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov columns.put(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id AS _id"); 532b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov columns.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE); 533127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov columns.put(AggregationExceptions.AGGREGATE_ID, 534127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov "contacts1." + Contacts.AGGREGATE_ID + " AS " + AggregationExceptions.AGGREGATE_ID); 535127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov columns.put(AggregationExceptions.CONTACT_ID, AggregationExceptionColumns.CONTACT_ID2); 536b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov sAggregationExceptionsProjectionMap = columns; 537b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 538c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedContactIdSelect = "SELECT " + Data.CONTACT_ID + " FROM " + Tables.DATA + " WHERE " 539c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + Data._ID + "=?"; 540c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedMimetypeSelect = "SELECT " + DataColumns.MIMETYPE_ID + " FROM " + Tables.DATA 541c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + " WHERE " + Data._ID + "=?"; 542c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedAggregateIdSelect = "SELECT " + Contacts.AGGREGATE_ID + " FROM " + Tables.CONTACTS 543c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + " WHERE " + Contacts._ID + "=(" + sNestedContactIdSelect + ")"; 544c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedContactIdListSelect = "SELECT " + Contacts._ID + " FROM " + Tables.CONTACTS 545c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + " WHERE " + Contacts.AGGREGATE_ID + "=(" + sNestedAggregateIdSelect + ")"; 546c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sSetPrimaryWhere = Data.CONTACT_ID + "=(" + sNestedContactIdSelect + ") AND " 547c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + DataColumns.MIMETYPE_ID + "=(" + sNestedMimetypeSelect + ")"; 548b67163a1088f09c59f324350662eb18772fac6b6Evan Millar sSetSuperPrimaryWhere = Data.CONTACT_ID + " IN (" + sNestedContactIdListSelect + ") AND " 549c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + DataColumns.MIMETYPE_ID + "=(" + sNestedMimetypeSelect + ")"; 550b67163a1088f09c59f324350662eb18772fac6b6Evan Millar sAggregatesInGroupSelect = AggregatesColumns.CONCRETE_ID + " IN (SELECT " 551b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + Contacts.AGGREGATE_ID + " FROM " + Tables.CONTACTS + " WHERE (" 552b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + ContactsColumns.CONCRETE_ID + " IN (SELECT " + Tables.DATA + "." 553b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + Data.CONTACT_ID + " FROM " + Tables.DATA_JOIN_MIMETYPES + " WHERE (" 554b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE + "' AND " 555b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + GroupMembership.GROUP_ROW_ID + "=(SELECT " + Tables.GROUPS + "." 556b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + Groups._ID + " FROM " + Tables.GROUPS + " WHERE " + Groups.TITLE + "=?)))))"; 5574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 5584f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 5593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 5603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov * Handles inserts and update for a specific Data type. 5613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov */ 5623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private abstract class DataRowHandler { 5633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 5643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov protected final String mMimetype; 5653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 5663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public DataRowHandler(String mimetype) { 5673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mMimetype = mimetype; 5683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 5693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 5703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 5713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov * Inserts a row into the {@link Data} table. 5723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov */ 5733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public long insert(SQLiteDatabase db, long contactId, ContentValues values) { 574e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov final long dataId = db.insert(Tables.DATA, null, values); 575e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov 576e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov Integer primary = values.getAsInteger(Data.IS_PRIMARY); 577e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov if (primary != null && primary != 0) { 578e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov setIsPrimary(dataId); 579e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov } 580e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov 581e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov fixContactDisplayName(db, contactId); 582e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov return dataId; 5833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 5843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 5853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 5863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov * Validates data and updates a {@link Data} row using the cursor, which contains 5873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov * the current data. 5883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov */ 5893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public void update(SQLiteDatabase db, ContentValues values, Cursor cursor) { 5903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov throw new UnsupportedOperationException(); 5913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 5923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 5933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public int delete(SQLiteDatabase db, Cursor c) { 5943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov long dataId = c.getLong(DataQuery.ID); 5953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov long contactId = c.getLong(DataQuery.CONTACT_ID); 5963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov boolean primary = c.getInt(DataQuery.IS_PRIMARY) != 0; 5973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov int count = db.delete(Tables.DATA, Data._ID + "=" + dataId, null); 5983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (count != 0 && primary) { 5993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov fixPrimary(db, contactId); 600e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov fixContactDisplayName(db, contactId); 6013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return count; 6033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private void fixPrimary(SQLiteDatabase db, long contactId) { 6063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov long newPrimaryId = findNewPrimaryDataId(db, contactId); 6073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (newPrimaryId != -1) { 6083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov ContactsProvider2.this.setIsPrimary(newPrimaryId); 6093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov protected long findNewPrimaryDataId(SQLiteDatabase db, long contactId) { 613e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov long primaryId = -1; 614e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov int primaryType = -1; 6153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Cursor c = queryData(db, contactId); 6163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov try { 617e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov while (c.moveToNext()) { 618e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov long dataId = c.getLong(DataQuery.ID); 619e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov int type = c.getInt(DataQuery.DATA2); 620e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) { 621e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov primaryId = dataId; 622e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov primaryType = type; 623e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov } 6243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } finally { 6263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov c.close(); 6273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 628e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov return primaryId; 629e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov } 630e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov 631e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov /** 632e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov * Returns the rank of a specific record type to be used in determining the primary 633e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov * row. Lower number represents higher priority. 634e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov */ 635e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov protected int getTypeRank(int type) { 636e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov return 0; 6373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov protected Cursor queryData(SQLiteDatabase db, long contactId) { 6403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov // TODO Lookup integer mimetype IDs' instead of joining for speed 64167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey return db.query(DataQuery.TABLE, DataQuery.COLUMNS, Data.CONTACT_ID + "=" 6423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov + contactId + " AND " + MimetypesColumns.MIMETYPE + "='" + mMimetype + "'", 6433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov null, null, null, null); 6443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov protected void fixContactDisplayName(SQLiteDatabase db, long contactId) { 647e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov if (!sDisplayNamePriorities.containsKey(mMimetype)) { 648e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov return; 649e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov } 650e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov 6513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov String bestDisplayName = null; 65267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Cursor c = db.query(DisplayNameQuery.TABLE, DisplayNameQuery.COLUMNS, 6533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Data.CONTACT_ID + "=" + contactId, null, null, null, null); 6543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov try { 6553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov int maxPriority = -1; 6563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov while (c.moveToNext()) { 6573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov String mimeType = c.getString(DisplayNameQuery.MIMETYPE); 6583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov boolean primary; 6593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov String name; 6603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) { 6623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov name = c.getString(DisplayNameQuery.DISPLAY_NAME); 6633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov primary = true; 6643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } else { 6653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov name = c.getString(DisplayNameQuery.DATA2); 6663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov primary = (c.getInt(DisplayNameQuery.IS_PRIMARY) != 0); 6673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (primary && name != null) { 6703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov Integer priority = sDisplayNamePriorities.get(mimeType); 6713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (priority != null && priority > maxPriority) { 6723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov maxPriority = priority; 6733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov bestDisplayName = name; 6743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } finally { 6793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov c.close(); 6803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov ContactsProvider2.this.setDisplayName(contactId, bestDisplayName); 6833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public class CustomDataRowHandler extends DataRowHandler { 6873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public CustomDataRowHandler(String mimetype) { 6893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov super(mimetype); 6903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 6923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public class StructuredNameRowHandler extends DataRowHandler { 6943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private final NameSplitter mNameSplitter; 6963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 6973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public StructuredNameRowHandler(NameSplitter nameSplitter) { 6983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov super(StructuredName.CONTENT_ITEM_TYPE); 6993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mNameSplitter = nameSplitter; 7003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov @Override 7033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public long insert(SQLiteDatabase db, long contactId, ContentValues values) { 7043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov fixStructuredNameComponents(values); 705e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov return super.insert(db, contactId, values); 7063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov @Override 7093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public void update(SQLiteDatabase db, ContentValues values, Cursor cursor) { 7103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov // TODO Parse the full name if it has changed and replace pre-existing piece parts. 7113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 7143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov * Parses the supplied display name, but only if the incoming values do not already contain 7153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov * structured name parts. Also, if the display name is not provided, generate one by 7163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov * concatenating first name and last name 7173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov * 7183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov * TODO see if the order of first and last names needs to be conditionally reversed for 7193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov * some locales, e.g. China. 7203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov */ 7213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private void fixStructuredNameComponents(ContentValues values) { 7223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov String fullName = values.getAsString(StructuredName.DISPLAY_NAME); 7233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (!TextUtils.isEmpty(fullName) 7243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov && TextUtils.isEmpty(values.getAsString(StructuredName.PREFIX)) 7253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov && TextUtils.isEmpty(values.getAsString(StructuredName.GIVEN_NAME)) 7263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov && TextUtils.isEmpty(values.getAsString(StructuredName.MIDDLE_NAME)) 7273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov && TextUtils.isEmpty(values.getAsString(StructuredName.FAMILY_NAME)) 7283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov && TextUtils.isEmpty(values.getAsString(StructuredName.SUFFIX))) { 7293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov NameSplitter.Name name = new NameSplitter.Name(); 7303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mNameSplitter.split(name, fullName); 7313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov values.put(StructuredName.PREFIX, name.getPrefix()); 7333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov values.put(StructuredName.GIVEN_NAME, name.getGivenNames()); 7343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov values.put(StructuredName.MIDDLE_NAME, name.getMiddleName()); 7353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov values.put(StructuredName.FAMILY_NAME, name.getFamilyName()); 7363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov values.put(StructuredName.SUFFIX, name.getSuffix()); 7373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (TextUtils.isEmpty(fullName)) { 7403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov String givenName = values.getAsString(StructuredName.GIVEN_NAME); 7413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov String familyName = values.getAsString(StructuredName.FAMILY_NAME); 7423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (TextUtils.isEmpty(givenName)) { 7433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov fullName = familyName; 7443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } else if (TextUtils.isEmpty(familyName)) { 7453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov fullName = givenName; 7463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } else { 7473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov fullName = givenName + " " + familyName; 7483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (!TextUtils.isEmpty(fullName)) { 7513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov values.put(StructuredName.DISPLAY_NAME, fullName); 7523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public class CommonDataRowHandler extends DataRowHandler { 7583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private final String mTypeColumn; 7603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private final String mLabelColumn; 7613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public CommonDataRowHandler(String mimetype, String typeColumn, String labelColumn) { 7633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov super(mimetype); 7643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mTypeColumn = typeColumn; 7653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mLabelColumn = labelColumn; 7663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov @Override 7693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public long insert(SQLiteDatabase db, long contactId, ContentValues values) { 7703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov int type; 7713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov String label; 7723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (values.containsKey(mTypeColumn)) { 7733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov type = values.getAsInteger(mTypeColumn); 7743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } else { 7753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov type = BaseTypes.TYPE_CUSTOM; 7763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (values.containsKey(mLabelColumn)) { 7783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov label = values.getAsString(mLabelColumn); 7793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } else { 7803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov label = null; 7813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (type != BaseTypes.TYPE_CUSTOM && label != null) { 7843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov throw new RuntimeException(mLabelColumn + " value can only be specified with " 7853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov + mTypeColumn + "=" + BaseTypes.TYPE_CUSTOM + "(custom)"); 7863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (type == BaseTypes.TYPE_CUSTOM && label == null) { 7893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov throw new RuntimeException(mLabelColumn + " value must be specified when " 7903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov + mTypeColumn + "=" + BaseTypes.TYPE_CUSTOM + "(custom)"); 7913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 793e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov return super.insert(db, contactId, values); 7943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 7953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 7963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov @Override 7973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public void update(SQLiteDatabase db, ContentValues values, Cursor cursor) { 7983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov // TODO read the data and check the constraint 7993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 8023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public class OrganizationDataRowHandler extends CommonDataRowHandler { 8033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 8043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public OrganizationDataRowHandler() { 8053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov super(Organization.CONTENT_ITEM_TYPE, Organization.TYPE, Organization.LABEL); 8063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 8083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov @Override 8093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public long insert(SQLiteDatabase db, long contactId, ContentValues values) { 8103cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov long id = super.insert(db, contactId, values); 8113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov fixContactDisplayName(db, contactId); 8123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return id; 8133cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8143cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 8153cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov @Override 8163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov protected int getTypeRank(int type) { 8173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov switch (type) { 8183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov case Organization.TYPE_WORK: return 0; 8193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov case Organization.TYPE_CUSTOM: return 1; 8203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov case Organization.TYPE_OTHER: return 2; 8213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov default: return 1000; 8223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 826e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov public class EmailDataRowHandler extends CommonDataRowHandler { 827e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov 828e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov public EmailDataRowHandler() { 829e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov super(Email.CONTENT_ITEM_TYPE, Email.TYPE, Email.LABEL); 830e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov } 831e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov 832e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov @Override 833e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov public long insert(SQLiteDatabase db, long contactId, ContentValues values) { 834e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov long id = super.insert(db, contactId, values); 835e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov fixContactDisplayName(db, contactId); 836e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov return id; 837e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov } 838e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov 839e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov @Override 840e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov protected int getTypeRank(int type) { 841e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov switch (type) { 842e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov case Email.TYPE_HOME: return 0; 843e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov case Email.TYPE_WORK: return 1; 844e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov case Email.TYPE_CUSTOM: return 2; 845e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov case Email.TYPE_OTHER: return 3; 846e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov default: return 1000; 847e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov } 848e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov } 849e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov } 850e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov 8513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public class PhoneDataRowHandler extends CommonDataRowHandler { 8523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 8533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public PhoneDataRowHandler() { 8543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov super(Phone.CONTENT_ITEM_TYPE, Phone.TYPE, Phone.LABEL); 8553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 8573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov @Override 8583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov public long insert(SQLiteDatabase db, long contactId, ContentValues values) { 859e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov ContentValues phoneValues = new ContentValues(); 860e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov String number = values.getAsString(Phone.NUMBER); 861e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov String normalizedNumber = null; 862e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov if (number != null) { 863e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov normalizedNumber = PhoneNumberUtils.getStrippedReversed(number); 864e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov values.put(PhoneColumns.NORMALIZED_NUMBER, normalizedNumber); 865e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov } 866e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov 8673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov long id = super.insert(db, contactId, values); 8683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 869e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov if (number != null) { 870e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov phoneValues.put(PhoneLookupColumns.CONTACT_ID, contactId); 871e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov phoneValues.put(PhoneLookupColumns.DATA_ID, id); 872e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, normalizedNumber); 873e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov db.insert(Tables.PHONE_LOOKUP, null, phoneValues); 874e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov } 8753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 8763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return id; 8773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 8793cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov @Override 8803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov protected int getTypeRank(int type) { 8813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov switch (type) { 8823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov case Phone.TYPE_MOBILE: return 0; 8833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov case Phone.TYPE_WORK: return 1; 8843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov case Phone.TYPE_HOME: return 2; 8853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov case Phone.TYPE_PAGER: return 3; 8863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov case Phone.TYPE_CUSTOM: return 4; 8873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov case Phone.TYPE_OTHER: return 5; 8883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov case Phone.TYPE_FAX_WORK: return 6; 8893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov case Phone.TYPE_FAX_HOME: return 7; 8903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov default: return 1000; 8913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 8943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 8953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private HashMap<String, DataRowHandler> mDataRowHandlers; 89653056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov private final ContactAggregationScheduler mAggregationScheduler; 8974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton private OpenHelper mOpenHelper; 89831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 899a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov private ContactAggregator mContactAggregator; 9004097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 901f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private LegacyApiSupport mLegacyApiSupport; 902a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 90320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private ContentValues mValues = new ContentValues(); 90420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 905a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public ContactsProvider2() { 90653056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov this(new ContactAggregationScheduler()); 907a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 908a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 909a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 910a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Constructor for testing. 911a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 91253056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov /* package */ ContactsProvider2(ContactAggregationScheduler scheduler) { 91353056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov mAggregationScheduler = scheduler; 914a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 9154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 9164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 9174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 918b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey final Context context = getContext(); 91935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 92031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov mOpenHelper = getOpenHelper(context); 921d51a83ac4f8032b62d9a23b90a8f43d6b7eb2dbbDmitri Plotnikov mLegacyApiSupport = new LegacyApiSupport(context, mOpenHelper, this); 92253056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov mContactAggregator = new ContactAggregator(context, mOpenHelper, mAggregationScheduler); 923a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 924d51a83ac4f8032b62d9a23b90a8f43d6b7eb2dbbDmitri Plotnikov final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 925c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement = db.compileStatement( 926c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar "UPDATE " + Tables.DATA + " SET " + Data.IS_PRIMARY 927c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + "=(_id=?) WHERE " + sSetPrimaryWhere); 928c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement = db.compileStatement( 929c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar "UPDATE " + Tables.DATA + " SET " + Data.IS_SUPER_PRIMARY 930c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + "=(_id=?) WHERE " + sSetSuperPrimaryWhere); 931f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mLastTimeContactedUpdate = db.compileStatement("UPDATE " + Tables.CONTACTS + " SET " 932f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov + Contacts.TIMES_CONTACTED + "=" + Contacts.TIMES_CONTACTED + "+1," 933f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov + Contacts.LAST_TIME_CONTACTED + "=? WHERE " + Contacts.AGGREGATE_ID + "=?"); 934a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 9353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mContactDisplayNameUpdate = db.compileStatement("UPDATE " + Tables.CONTACTS + " SET " 9363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov + ContactsColumns.DISPLAY_NAME + "=? WHERE " + Contacts._ID + "=?"); 9373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 93828f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar mNameSplitter = new NameSplitter( 93928f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_name_prefixes), 94028f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_last_name_prefixes), 94128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_name_suffixes), 94228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_name_conjunctions)); 9434097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 9443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers = new HashMap<String, DataRowHandler>(); 9453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 946e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, new EmailDataRowHandler()); 9473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE, 9483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov new CommonDataRowHandler(Im.CONTENT_ITEM_TYPE, Im.TYPE, Im.LABEL)); 94967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler( 95067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, StructuredPostal.LABEL)); 9513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, new OrganizationDataRowHandler()); 9523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, new PhoneDataRowHandler()); 95367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler( 95467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE, Nickname.LABEL)); 9553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE, 9563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov new StructuredNameRowHandler(mNameSplitter)); 9573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 9581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return (db != null); 9594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 9604f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 96131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /* Visible for testing */ 96231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov protected OpenHelper getOpenHelper(final Context context) { 96331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov return OpenHelper.getInstance(context); 96431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 96531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 966a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov @Override 967a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov protected void finalize() throws Throwable { 968a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov if (mContactAggregator != null) { 969a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov mContactAggregator.quit(); 970a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 971a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 972a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov super.finalize(); 973a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 974a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 975a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 976a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 977a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 978a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /* package */ void wipeData() { 979a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov mOpenHelper.wipeData(); 980a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 981a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 982a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 983a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Called when a change has been made. 984a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 985a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param uri the uri that the change was made to 986a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 987a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton private void onChange(Uri uri) { 988a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null); 989a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 990a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 9914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 9924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean isTemporary() { 9934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return false; 9944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 9954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 9963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private DataRowHandler getDataRowHandler(final String mimeType) { 9973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataRowHandler handler = mDataRowHandlers.get(mimeType); 9983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (handler == null) { 9993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov handler = new CustomDataRowHandler(mimeType); 10003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(mimeType, handler); 10013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 10023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return handler; 10033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 10043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 10054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 10064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Uri insert(Uri uri, ContentValues values) { 1007a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 1008a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 100935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1010a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 101135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 101235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana id = mOpenHelper.getSyncState().insert(mOpenHelper.getWritableDatabase(), values); 101335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 101435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 10156bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES: { 1016f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov insertAggregate(values); 10176bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 10186bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 10196bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 1020a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case CONTACTS: { 1021f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana final Account account = readAccountFromQueryParams(uri); 1022f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana id = insertContact(values, account); 1023a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 1024a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1025a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1026a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case CONTACTS_DATA: { 1027a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton values.put(Data.CONTACT_ID, uri.getPathSegments().get(1)); 1028035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana id = insertData(values); 1029a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 1030a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1031a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1032a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case DATA: { 1033035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana id = insertData(values); 1034a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 1035a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1036a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1037ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 1038ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final Account account = readAccountFromQueryParams(uri); 1039ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey id = insertGroup(values, account); 1040ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1041ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1042ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 10431f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case PRESENCE: { 10441f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey id = insertPresence(values); 10451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 10461f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 10471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1048a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 1049f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.insert(uri, values); 1050a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1051a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 10527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 10537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 10547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 10557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 10567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final Uri result = ContentUris.withAppendedId(uri, id); 1057a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton onChange(result); 1058a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return result; 1059a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1060a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1061a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 1062035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * If account is non-null then store it in the values. If the account is already 1063035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * specified in the values then it must be consistent with the account, if it is non-null. 1064035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * @param values the ContentValues to read from and update 1065035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * @param account the explicitly provided Account 1066035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * @return false if the accounts are inconsistent 10677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 1068035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private boolean resolveAccount(ContentValues values, Account account) { 1069035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana // If either is specified then both must be specified. 1070035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountName = values.getAsString(Contacts.ACCOUNT_NAME); 1071035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountType = values.getAsString(Contacts.ACCOUNT_TYPE); 1072035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (!TextUtils.isEmpty(accountName) || !TextUtils.isEmpty(accountType)) { 1073035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final Account valuesAccount = new Account(accountName, accountType); 1074035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (account != null && !valuesAccount.equals(account)) { 1075035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana return false; 1076035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 1077035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana account = valuesAccount; 1078035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 1079035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (account != null) { 1080035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana values.put(Contacts.ACCOUNT_NAME, account.mName); 1081035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana values.put(Contacts.ACCOUNT_TYPE, account.mType); 1082035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 1083035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana return true; 10847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 10857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 10867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 10876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * Inserts an item in the aggregates table 10886bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 10896bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 10906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 10916bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 10926bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private long insertAggregate(ContentValues values) { 1093a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov throw new UnsupportedOperationException("Aggregates are created automatically"); 10946bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 10956bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 10966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 1097a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the contacts table 1098a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 1099a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 1100f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana * @param account the account this contact should be associated with. may be null. 1101a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 1102a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 1103f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana private long insertContact(ContentValues values, Account account) { 11046bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /* 11056bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * The contact record is inserted in the contacts table, but it needs to 11066bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * be processed by the aggregator before it will be returned by the 11076bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * "aggregates" queries. 11086bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 1109a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 11106bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 1111a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov ContentValues overriddenValues = new ContentValues(values); 1112a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov overriddenValues.putNull(Contacts.AGGREGATE_ID); 1113f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana if (!resolveAccount(overriddenValues, account)) { 11147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return -1; 11157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 11167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 1117f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov long contactId = db.insert(Tables.CONTACTS, Contacts.AGGREGATE_ID, overriddenValues); 1118f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov 1119f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov int aggregationMode = Contacts.AGGREGATION_MODE_DEFAULT; 1120f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov if (values.containsKey(Contacts.AGGREGATION_MODE)) { 1121f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov aggregationMode = values.getAsInteger(Contacts.AGGREGATION_MODE); 1122f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 1123a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1124f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov triggerAggregation(contactId, aggregationMode); 1125a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1126f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return contactId; 1127a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1128a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1129a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 1130a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 1131a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 1132a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 1133a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 1134a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 1135035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private long insertData(ContentValues values) { 1136f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov int aggregationMode = Contacts.AGGREGATION_MODE_DISABLED; 1137a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1138a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1139a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 1140a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton db.beginTransaction(); 1141a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton try { 114220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.clear(); 114320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.putAll(values); 114420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 114520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov long contactId = mValues.getAsLong(Data.CONTACT_ID); 1146a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 114767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey // Replace package with internal mapping 114820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov final String packageName = mValues.getAsString(Data.RES_PACKAGE); 114967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (packageName != null) { 115020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName)); 115167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 115220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 115367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 1154619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Replace mimetype with internal mapping 115520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov final String mimeType = mValues.getAsString(Data.MIMETYPE); 115620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (TextUtils.isEmpty(mimeType)) { 115720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov throw new RuntimeException(Data.MIMETYPE + " is required"); 115820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 115920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 116020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.put(DataColumns.MIMETYPE_ID, mOpenHelper.getMimeTypeId(mimeType)); 116120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 1162508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 11633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) { 116420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean containsGroupSourceId = mValues.containsKey(GroupMembership.GROUP_SOURCE_ID); 116520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean containsGroupId = mValues.containsKey(GroupMembership.GROUP_ROW_ID); 11669261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (containsGroupSourceId && containsGroupId) { 11679261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana throw new IllegalArgumentException( 11689261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana "you are not allowed to set both the GroupMembership.GROUP_SOURCE_ID " 11699261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana + "and GroupMembership.GROUP_ROW_ID"); 11709261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 11719261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 11729261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (!containsGroupSourceId && !containsGroupId) { 11739261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana throw new IllegalArgumentException( 11749261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana "you must set exactly one of GroupMembership.GROUP_SOURCE_ID " 11759261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana + "and GroupMembership.GROUP_ROW_ID"); 11769261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 11779261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 11789261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (containsGroupSourceId) { 117920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov final String sourceId = mValues.getAsString(GroupMembership.GROUP_SOURCE_ID); 11809261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana final long groupId = getOrMakeGroup(db, contactId, sourceId); 118120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(GroupMembership.GROUP_SOURCE_ID); 118220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.put(GroupMembership.GROUP_ROW_ID, groupId); 11839261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 11844097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov } 11854097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 118620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov id = getDataRowHandler(mimeType).insert(db, contactId, mValues); 1187a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1188f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov aggregationMode = mContactAggregator.markContactForAggregation(contactId); 1189a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1190a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton db.setTransactionSuccessful(); 1191a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } finally { 1192a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton db.endTransaction(); 1193a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1194a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1195f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov triggerAggregation(id, aggregationMode); 1196a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 11974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 11984f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1199f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private void triggerAggregation(long contactId, int aggregationMode) { 1200f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov switch (aggregationMode) { 1201f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov case Contacts.AGGREGATION_MODE_DEFAULT: 1202f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mContactAggregator.schedule(); 1203f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov break; 1204f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov 1205f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov case Contacts.AGGREGATION_MODE_IMMEDITATE: 1206f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mContactAggregator.aggregateContact(contactId); 1207f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov break; 1208f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov 1209f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov case Contacts.AGGREGATION_MODE_DISABLED: 1210f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov // Do nothing 1211f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov break; 1212f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 1213f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 1214f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov 1215a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 12169261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * Returns the group id of the group with sourceId and the same account as contactId. 12179261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * If the group doesn't already exist then it is first created, 12189261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @param db SQLiteDatabase to use for this operation 12199261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @param contactId the contact this group is associated with 12209261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @param sourceId the sourceIf of the group to query or create 12219261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @return the group id of the existing or created group 12229261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @throws IllegalArgumentException if the contact is not associated with an account 12239261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @throws IllegalStateException if a group needs to be created but the creation failed 12249261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana */ 12259261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana private long getOrMakeGroup(SQLiteDatabase db, long contactId, String sourceId) { 12269261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana Account account = null; 122767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Cursor c = db.query(ContactsQuery.TABLE, ContactsQuery.PROJECTION, Contacts._ID + "=" 122867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + contactId, null, null, null, null); 12299261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana try { 12309261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (c.moveToNext()) { 123167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey final String accountName = c.getString(ContactsQuery.ACCOUNT_NAME); 123267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey final String accountType = c.getString(ContactsQuery.ACCOUNT_TYPE); 12339261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { 12349261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana account = new Account(accountName, accountType); 12359261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 12369261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 12379261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } finally { 12389261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana c.close(); 12399261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 12409261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (account == null) { 12419261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana throw new IllegalArgumentException("if the groupmembership only " 12429261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana + "has a sourceid the the contact must be associate with " 12439261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana + "an account"); 12449261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 12459261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 12469261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana // look up the group that contains this sourceId and has the same account name and type 12479261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana // as the contact refered to by contactId 12489261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana c = db.query(Tables.GROUPS, new String[]{Contacts._ID}, 12499261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana Clauses.GROUP_HAS_ACCOUNT_AND_SOURCE_ID, 12509261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana new String[]{sourceId, account.mName, account.mType}, null, null, null); 12519261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana try { 12529261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (c.moveToNext()) { 12539261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana return c.getLong(0); 12549261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } else { 12559261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana ContentValues groupValues = new ContentValues(); 12569261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana groupValues.put(Groups.ACCOUNT_NAME, account.mName); 12579261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana groupValues.put(Groups.ACCOUNT_TYPE, account.mType); 12589261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana groupValues.put(Groups.SOURCE_ID, sourceId); 12599261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana long groupId = db.insert(Tables.GROUPS, Groups.ACCOUNT_NAME, groupValues); 12609261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (groupId < 0) { 12619261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana throw new IllegalStateException("unable to create a new group with " 12629261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana + "this sourceid: " + groupValues); 12639261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 12649261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana return groupId; 12659261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 12669261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } finally { 12679261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana c.close(); 12689261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 12699261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 12709261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 12719261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** 127220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov * Delete data row by row so that fixing of primaries etc work correctly. 127320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov */ 127420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private int deleteData(String selection, String[] selectionArgs) { 127520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 127620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int count = 0; 127720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov db.beginTransaction(); 127820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 127920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 128020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 128120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 128220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataIdQuery.COLUMNS, selection, selectionArgs, null); 128320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 128420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov while(c.moveToNext()) { 128520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov long dataId = c.getLong(DataIdQuery._ID); 128620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov count += deleteData(dataId); 128720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 128820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 128920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 129020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 129120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov db.setTransactionSuccessful(); 129220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 129320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov db.endTransaction(); 129420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 129520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 129620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return count; 129720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 129820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 129920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov public int deleteData(long dataId, String[] allowedMimeTypes) { 130020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 130120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov Cursor c = db.query(DataQuery.TABLE, DataQuery.COLUMNS, 130220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov DataColumns.CONCRETE_ID + "=" + dataId, null, null, null, null); 130320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov // TODO apply restrictions 130420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 130520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!c.moveToFirst()) { 130620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return 0; 130720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 130820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 130920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String mimeType = c.getString(DataQuery.MIMETYPE); 131020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean valid = false; 131120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov for (int i = 0; i < allowedMimeTypes.length; i++) { 131220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (TextUtils.equals(mimeType, allowedMimeTypes[i])) { 131320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov valid = true; 131420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 131520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 131620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 131720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 131820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!valid) { 131920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov throw new RuntimeException("Data type mismatch: expected " 132020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov + Lists.newArrayList(allowedMimeTypes)); 132120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 132220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 132320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return getDataRowHandler(mimeType).delete(db, c); 132420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 132520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 132620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 132720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 132820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 132920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov /** 1330ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Delete the given {@link Data} row, fixing up any {@link Aggregates} 1331ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * primaries that reference it. 1332ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 1333ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private int deleteData(long dataId) { 1334ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1335ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1336ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long mimePhone = mOpenHelper.getMimeTypeId(Phone.CONTENT_ITEM_TYPE); 1337ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long mimeEmail = mOpenHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE); 1338ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1339ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Check to see if the data about to be deleted was a super-primary on 1340ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // the parent aggregate, and set flags to fix-up once deleted. 1341ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long aggId = -1; 1342ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long mimeId = -1; 1343ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String dataRaw = null; 1344ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey boolean fixOptimal = false; 1345ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey boolean fixFallback = false; 1346ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1347ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Cursor cursor = null; 1348ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey try { 134967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey cursor = db.query(DataAggregatesQuery.TABLE, DataAggregatesQuery.PROJECTION, 135067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey DataColumns.CONCRETE_ID + "=" + dataId, null, null, null, null); 1351ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (cursor.moveToFirst()) { 135267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey aggId = cursor.getLong(DataAggregatesQuery.AGGREGATE_ID); 135367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey mimeId = cursor.getLong(DataAggregatesQuery.MIMETYPE_ID); 1354ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 135567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataRaw = cursor.getString(DataAggregatesQuery.PHONE_NUMBER); 135667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey fixOptimal = (cursor.getLong(DataAggregatesQuery.OPTIMAL_PHONE_ID) == dataId); 135767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey fixFallback = (cursor.getLong(DataAggregatesQuery.FALLBACK_PHONE_ID) == dataId); 1358ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 135967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataRaw = cursor.getString(DataAggregatesQuery.EMAIL_DATA); 136067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey fixOptimal = (cursor.getLong(DataAggregatesQuery.OPTIMAL_EMAIL_ID) == dataId); 136167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey fixFallback = (cursor.getLong(DataAggregatesQuery.FALLBACK_EMAIL_ID) == dataId); 1362ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1363ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1364ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } finally { 1365ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (cursor != null) { 1366ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor.close(); 1367ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = null; 1368ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1369ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1370ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1371ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Delete the requested data item. 1372ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey int dataDeleted = db.delete(Tables.DATA, Data._ID + "=" + dataId, null); 1373ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1374ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Fix-up any super-primary values that are now invalid. 1375ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (fixOptimal || fixFallback) { 1376ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final ContentValues values = new ContentValues(); 1377ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final StringBuilder scoreClause = new StringBuilder(); 1378ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1379ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final String SCORE = "score"; 1380ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1381ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Build scoring clause that will first pick data items under the 1382ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // same aggregate that have identical values, otherwise fall back to 1383ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // normal primary scoring from the member contacts. 1384ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append("(CASE WHEN "); 1385ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 1386ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append(Phone.NUMBER); 1387ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 1388ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append(Email.DATA); 1389ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1390ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append("="); 1391ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey DatabaseUtils.appendEscapedSQLString(scoreClause, dataRaw); 1392ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append(" THEN 2 ELSE " + Data.IS_PRIMARY + " END) AS " + SCORE); 1393ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1394ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final String[] PROJ_PRIMARY = new String[] { 1395ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey DataColumns.CONCRETE_ID, 1396ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Contacts.IS_RESTRICTED, 1397ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.toString(), 1398ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 1399ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1400ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final int COL_DATA_ID = 0; 1401ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final int COL_IS_RESTRICTED = 1; 140267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey final int COL_SCORE = 2; 1403ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1404ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = db.query(Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES, PROJ_PRIMARY, 1405ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.CONCRETE_ID + "=" + aggId + " AND " + DataColumns.MIMETYPE_ID 1406ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "=" + mimeId, null, null, null, SCORE); 1407ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1408ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (fixOptimal) { 1409ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String colId = null; 141067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey String colIsRestricted = null; 1411ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 1412ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID; 141367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey colIsRestricted = AggregatesColumns.OPTIMAL_PRIMARY_PHONE_IS_RESTRICTED; 1414ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 1415ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID; 141667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey colIsRestricted = AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_IS_RESTRICTED; 1417ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1418ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1419ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Start by replacing with null, since fixOptimal told us that 1420ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // the previous aggregate values are bad. 1421ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.putNull(colId); 142267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey values.putNull(colIsRestricted); 1423ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1424ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // When finding a new optimal primary, we only care about the 1425ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // highest scoring value, regardless of source. 1426ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (cursor.moveToFirst()) { 1427ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long newOptimal = cursor.getLong(COL_DATA_ID); 142867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey final long newIsRestricted = cursor.getLong(COL_IS_RESTRICTED); 1429ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1430ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (newOptimal != 0) { 1431ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.put(colId, newOptimal); 1432ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 143367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (newIsRestricted != 0) { 143467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey values.put(colIsRestricted, newIsRestricted); 1435ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1436ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1437ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1438ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1439ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (fixFallback) { 1440ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String colId = null; 1441ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 1442ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID; 1443ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 1444ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID; 1445ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1446ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1447ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Start by replacing with null, since fixFallback told us that 1448ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // the previous aggregate values are bad. 1449ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.putNull(colId); 1450ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1451ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // The best fallback value is the highest scoring data item that 1452ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // hasn't been restricted. 1453ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor.moveToPosition(-1); 1454ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey while (cursor.moveToNext()) { 1455ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final boolean isRestricted = (cursor.getInt(COL_IS_RESTRICTED) == 1); 1456ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (!isRestricted) { 1457ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.put(colId, cursor.getLong(COL_DATA_ID)); 1458ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1459ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1460ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1461ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1462ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1463ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Push through any aggregate updates we have 1464ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (values.size() > 0) { 1465ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey db.update(Tables.AGGREGATES, values, AggregatesColumns.CONCRETE_ID + "=" + aggId, 1466ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey null); 1467ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1468ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1469ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1470ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return dataDeleted; 1471ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1472ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1473ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 1474ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 1475ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 1476ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private long insertGroup(ContentValues values, Account account) { 1477ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1478ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1479ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContentValues overriddenValues = new ContentValues(values); 1480ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (!resolveAccount(overriddenValues, account)) { 1481ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return -1; 1482ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1483ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1484ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 148567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey final String packageName = overriddenValues.getAsString(Groups.RES_PACKAGE); 148667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (packageName != null) { 148767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey overriddenValues.put(GroupsColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName)); 148867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 148967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey overriddenValues.remove(Groups.RES_PACKAGE); 1490ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1491ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return db.insert(Tables.GROUPS, Groups.TITLE, overriddenValues); 1492ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1493ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1494ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 14951f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey * Inserts a presence update. 14961f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 149770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov public long insertPresence(ContentValues values) { 14981f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 14991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final String handle = values.getAsString(Presence.IM_HANDLE); 15001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final String protocol = values.getAsString(Presence.IM_PROTOCOL); 15011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (TextUtils.isEmpty(handle) || TextUtils.isEmpty(protocol)) { 15021f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey throw new IllegalArgumentException("IM_PROTOCOL and IM_HANDLE are required"); 15031f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 15041f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 15051f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // TODO: generalize to allow other providers to match against email 15061f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey boolean matchEmail = GTALK_PROTOCOL_STRING.equals(protocol); 15071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 150870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov StringBuilder selection = new StringBuilder(); 15091f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String[] selectionArgs; 15101f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (matchEmail) { 151170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov selection.append("(" + Clauses.WHERE_IM_MATCHES + ") OR (" 151270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov + Clauses.WHERE_EMAIL_MATCHES + ")"); 15131f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey selectionArgs = new String[] { protocol, handle, handle }; 15141f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 151570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov selection.append(Clauses.WHERE_IM_MATCHES); 15161f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey selectionArgs = new String[] { protocol, handle }; 15171f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 15181f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 151970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov if (values.containsKey(Presence.DATA_ID)) { 152070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov selection.append(" AND " + DataColumns.CONCRETE_ID + "=") 152170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov .append(values.getAsLong(Presence.DATA_ID)); 152270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 152370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 152470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov if (values.containsKey(Presence.CONTACT_ID)) { 152570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov selection.append(" AND " + DataColumns.CONCRETE_CONTACT_ID + "=") 152670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov .append(values.getAsLong(Presence.CONTACT_ID)); 152770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 152870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 152970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov selection.append(" AND ").append(getContactsRestrictionExceptions()); 153070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 15311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey long dataId = -1; 1532c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov long contactId = -1; 153370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 15341f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 15351f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 153670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov cursor = db.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 153770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov selection.toString(), selectionArgs, null, null, null); 15381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 153967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataId = cursor.getLong(DataContactsQuery.DATA_ID); 1540c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov contactId = cursor.getLong(DataContactsQuery.CONTACT_ID); 15411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 15421f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 15431f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 15441f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 15451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 154631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 154731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 154831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 15491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 15501f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 15511f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey values.put(Presence.DATA_ID, dataId); 1552c62855331805c2744a097ef6ea625652197bfb87Dmitri Plotnikov values.put(Presence.CONTACT_ID, contactId); 15531f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 15541f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // Insert the presence update 15551f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey long presenceId = db.replace(Tables.PRESENCE, null, values); 15561f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return presenceId; 15571f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 15581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 15594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 15604f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public int delete(Uri uri, String selection, String[] selectionArgs) { 1561508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1562508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 1563508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 156435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 156535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana return mOpenHelper.getSyncState().delete(db, selection, selectionArgs); 156635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 15676bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES_ID: { 15686bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov long aggregateId = ContentUris.parseId(uri); 15696bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 15706bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov // Remove references to the aggregate first 15716bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov ContentValues values = new ContentValues(); 15726bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov values.putNull(Contacts.AGGREGATE_ID); 1573b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.update(Tables.CONTACTS, values, Contacts.AGGREGATE_ID + "=" + aggregateId, null); 15746bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 1575b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return db.delete(Tables.AGGREGATES, BaseColumns._ID + "=" + aggregateId, null); 15766bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 15776bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 1578508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case CONTACTS_ID: { 1579508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long contactId = ContentUris.parseId(uri); 1580b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey int contactsDeleted = db.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null); 1581b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey int dataDeleted = db.delete(Tables.DATA, Data.CONTACT_ID + "=" + contactId, null); 1582508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey return contactsDeleted + dataDeleted; 1583508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 1584508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 158520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 158620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return deleteData(selection, selectionArgs); 158720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 158820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 1589508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: { 1590508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 1591ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return deleteData(dataId); 1592ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1593ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1594ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 1595ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 1596ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long groupMembershipMimetypeId = mOpenHelper 1597ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 1598ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey int groupsDeleted = db.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 1599ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey int dataDeleted = db.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 1600ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 1601ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + groupId, null); 1602ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mOpenHelper.updateAllVisible(); 1603ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return groupsDeleted + dataDeleted; 1604508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 1605508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 16061f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case PRESENCE: { 16071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return db.delete(Tables.PRESENCE, null, null); 16081f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 16091f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1610508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey default: 16113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return mLegacyApiSupport.delete(uri, selection, selectionArgs); 1612508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 16134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 16144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1615f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana private static Account readAccountFromQueryParams(Uri uri) { 1616035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String name = uri.getQueryParameter(Contacts.ACCOUNT_NAME); 1617035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String type = uri.getQueryParameter(Contacts.ACCOUNT_TYPE); 1618f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana if (TextUtils.isEmpty(name) || TextUtils.isEmpty(type)) { 1619f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana return null; 1620f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana } 1621f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana return new Account(name, type); 1622f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana } 1623f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana 1624ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 16254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 16264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 162700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 162835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 162900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 163000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 163100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 163235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 163335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana return mOpenHelper.getSyncState().update(db, values, selection, selectionArgs); 163435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1635c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar // TODO(emillar): We will want to disallow editing the aggregates table at some point. 163600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar case AGGREGATES: { 163700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar count = db.update(Tables.AGGREGATES, values, selection, selectionArgs); 163800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 163900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 164000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 164100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar case AGGREGATES_ID: { 1642d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov count = updateAggregateData(db, ContentUris.parseId(uri), values); 1643c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 1644c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 1645c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 164620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 164720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov count = updateData(values, selection, selectionArgs); 164820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 164920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 1650c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 165120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA_ID: { 165220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov count = updateData(ContentUris.parseId(uri), values); 165300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 165400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 16557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 16567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS: { 16577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana count = db.update(Tables.CONTACTS, values, selection, selectionArgs); 16587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 16597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 16607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 16617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS_ID: { 16627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String selectionWithId = (Contacts._ID + " = " + ContentUris.parseId(uri) + " ") 16637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana + (selection == null ? "" : " AND " + selection); 16647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana count = db.update(Tables.CONTACTS, values, selectionWithId, selectionArgs); 16657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana Log.i(TAG, "Selection is: " + selectionWithId); 16667e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 16677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 16687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 1669ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 1670ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey count = db.update(Tables.GROUPS, values, selection, selectionArgs); 1671ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mOpenHelper.updateAllVisible(); 1672ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1673ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1674ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1675ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 1676ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 1677ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String selectionWithId = (Groups._ID + "=" + groupId + " ") 1678ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + (selection == null ? "" : " AND " + selection); 1679ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey count = db.update(Tables.GROUPS, values, selectionWithId, selectionArgs); 1680ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1681ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // If changing visibility, then update aggregates 1682ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (values.containsKey(Groups.GROUP_VISIBLE)) { 1683ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mOpenHelper.updateAllVisible(); 1684ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1685ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1686ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1687ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1688ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1689127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 1690127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov count = updateAggregationException(db, values); 1691b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 1692b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1693b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 16947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana default: 1695f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.update(uri, values, selection, selectionArgs); 169600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 169700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 169800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar if (count > 0) { 169900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar getContext().getContentResolver().notifyChange(uri, null); 170000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 170100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 17024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 17034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 170420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private int updateData(ContentValues values, String selection, 170520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String[] selectionArgs) { 170620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 170720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int count = 0; 170820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov db.beginTransaction(); 170920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 171020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 171120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 171220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 171320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataIdQuery.COLUMNS, selection, selectionArgs, null); 171420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 171520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov while(c.moveToNext()) { 171620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov long dataId = c.getLong(DataIdQuery._ID); 171720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov count += updateData(dataId, values); 171820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 171920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 172020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 172120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 172220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov db.setTransactionSuccessful(); 172320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 172420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov db.endTransaction(); 172520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 172620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 172720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return count; 172820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 172920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 173020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private int updateData(long dataId, ContentValues values) { 173120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 173220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 173320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.clear(); 173420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.putAll(values); 173520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data._ID); 173620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.CONTACT_ID); 173720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 173820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 173920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String packageName = values.getAsString(Data.RES_PACKAGE); 174020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (packageName != null) { 174120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 174220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName)); 174320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 174420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 174570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov boolean containsIsSuperPrimary = mValues.containsKey(Data.IS_SUPER_PRIMARY); 174670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov boolean containsIsPrimary = mValues.containsKey(Data.IS_PRIMARY); 174720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 174820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov // Remove primary or super primary values being set to 0. This is disallowed by the 174920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov // content provider. 175070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov if (containsIsSuperPrimary && mValues.getAsInteger(Data.IS_SUPER_PRIMARY) == 0) { 175120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov containsIsSuperPrimary = false; 175270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov mValues.remove(Data.IS_SUPER_PRIMARY); 175320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 175470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov if (containsIsPrimary && mValues.getAsInteger(Data.IS_PRIMARY) == 0) { 175520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov containsIsPrimary = false; 175670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov mValues.remove(Data.IS_PRIMARY); 175720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 175820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 175920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (containsIsSuperPrimary) { 176020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov setIsSuperPrimary(dataId); 176120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov setIsPrimary(dataId); 176220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 176320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov // Now that we've taken care of setting these, remove them from "values". 176470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov mValues.remove(Data.IS_SUPER_PRIMARY); 176520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (containsIsPrimary) { 176670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov mValues.remove(Data.IS_PRIMARY); 176720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 176820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } else if (containsIsPrimary) { 176920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov setIsPrimary(dataId); 177020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 177120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov // Now that we've taken care of setting this, remove it from "values". 177270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov mValues.remove(Data.IS_PRIMARY); 177320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 177420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 177570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov if (mValues.size() > 0) { 177670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov return db.update(Tables.DATA, mValues, Data._ID + " = " + dataId, null); 177720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 177820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return 0; 177920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 178020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 1781d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov private int updateAggregateData(SQLiteDatabase db, long aggregateId, ContentValues values) { 1782d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1783d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // First update all constituent contacts 1784f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov ContentValues optionValues = new ContentValues(5); 1785f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov OpenHelper.copyStringValue(optionValues, Contacts.CUSTOM_RINGTONE, 1786f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov values, Aggregates.CUSTOM_RINGTONE); 1787f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov OpenHelper.copyLongValue(optionValues, Contacts.SEND_TO_VOICEMAIL, 1788f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov values, Aggregates.SEND_TO_VOICEMAIL); 1789f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov OpenHelper.copyLongValue(optionValues, Contacts.LAST_TIME_CONTACTED, 1790f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov values, Aggregates.LAST_TIME_CONTACTED); 1791f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov OpenHelper.copyLongValue(optionValues, Contacts.TIMES_CONTACTED, 1792f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov values, Aggregates.TIMES_CONTACTED); 1793f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov OpenHelper.copyLongValue(optionValues, Contacts.STARRED, 1794f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov values, Aggregates.STARRED); 1795d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1796d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 1797d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov if (optionValues.size() == 0) { 1798d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 1799d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1800d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1801f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov db.update(Tables.CONTACTS, optionValues, Contacts.AGGREGATE_ID + "=" + aggregateId, null); 1802f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return db.update(Tables.AGGREGATES, values, Aggregates._ID + "=" + aggregateId, null); 1803f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 1804d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1805f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov public void updateContactTime(long aggregateId, long lastTimeContacted) { 1806f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mLastTimeContactedUpdate.bindLong(1, lastTimeContacted); 1807f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mLastTimeContactedUpdate.bindLong(2, aggregateId); 1808f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mLastTimeContactedUpdate.execute(); 1809d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1810d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1811127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private static class ContactPair { 1812127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov final long contactId1; 1813127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov final long contactId2; 1814127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1815127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov /** 1816127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov * Constructor that ensures that this.contactId1 < this.contactId2 1817127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov */ 1818127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov public ContactPair(long contactId1, long contactId2) { 1819127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov if (contactId1 < contactId2) { 1820127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId1 = contactId1; 1821127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId2 = contactId2; 1822127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } else { 1823127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId2 = contactId1; 1824127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId1 = contactId2; 1825127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1826127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1827127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 182880c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 1829127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 1830127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 1831127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov long aggregateId = values.getAsInteger(AggregationExceptions.AGGREGATE_ID); 1832127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov long contactId = values.getAsInteger(AggregationExceptions.CONTACT_ID); 183380c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 1834127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // First, we build a list of contactID-contactID pairs for the given aggregate and contact. 1835127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov ArrayList<ContactPair> pairs = new ArrayList<ContactPair>(); 183667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Cursor c = db.query(ContactsQuery.TABLE, ContactsQuery.PROJECTION, Contacts.AGGREGATE_ID 183767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + "=" + aggregateId, null, null, null, null); 1838127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov try { 1839127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov while (c.moveToNext()) { 184067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey long aggregatedContactId = c.getLong(ContactsQuery.CONTACT_ID); 1841e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov if (aggregatedContactId != contactId) { 1842e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov pairs.add(new ContactPair(aggregatedContactId, contactId)); 1843e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov } 1844b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1845b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } finally { 1846b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov c.close(); 1847b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1848127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1849127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // Now we iterate through all contact pairs to see if we need to insert/delete/update 1850127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // the corresponding exception 1851127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 1852127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 1853127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov for (ContactPair pair : pairs) { 1854127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov final String whereClause = 1855127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov AggregationExceptionColumns.CONTACT_ID1 + "=" + pair.contactId1 + " AND " 1856127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov + AggregationExceptionColumns.CONTACT_ID2 + "=" + pair.contactId2; 1857127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 1858127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, whereClause, null); 1859127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } else { 1860127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues.put(AggregationExceptionColumns.CONTACT_ID1, pair.contactId1); 1861127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues.put(AggregationExceptionColumns.CONTACT_ID2, pair.contactId2); 1862127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 1863127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues); 1864127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1865127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1866127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1867f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov int aggregationMode = mContactAggregator.markContactForAggregation(contactId); 1868f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov if (aggregationMode != Contacts.AGGREGATION_MODE_DISABLED) { 1869f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mContactAggregator.aggregateContact(db, contactId); 1870f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC 1871f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov || exceptionType == AggregationExceptions.TYPE_KEEP_OUT) { 1872f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mContactAggregator.updateAggregateData(aggregateId); 1873f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 18747a39bf269294a8130ddd463460b9b36cf4ff74a8Dmitri Plotnikov } 1875127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1876127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 1877127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 1878127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 1879b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1880b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 1881619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1882619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Test if a {@link String} value appears in the given list. 1883619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1884619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private boolean isContained(String[] array, String value) { 1885bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar if (array != null) { 1886bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar for (String test : array) { 1887bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar if (value.equals(test)) { 1888bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar return true; 1889bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar } 1890619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1891619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1892619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return false; 1893619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1894619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1895619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1896619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Test if a {@link String} value appears in the given list, and add to the 1897619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * array if the value doesn't already appear. 1898619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1899619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private String[] assertContained(String[] array, String value) { 1900bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar if (array == null) { 1901bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar array = new String[] {value}; 1902bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar } else if (!isContained(array, value)) { 1903619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey String[] newArray = new String[array.length + 1]; 1904619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey System.arraycopy(array, 0, newArray, 0, array.length); 1905619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey newArray[array.length] = value; 1906619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey array = newArray; 1907619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1908619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return array; 1909619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1910619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 19114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 19124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 19134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 19144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 191535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1916d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 19171f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 19181f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String limit = null; 1919bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar String aggregateIdColName = Tables.AGGREGATES + "." + Aggregates._ID; 19204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1921619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: Consider writing a test case for RestrictionExceptions when you 1922619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // write a new query() block to make sure it protects restricted data. 1923a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 19244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 192535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 192635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana return mOpenHelper.getSyncState().query(db, projection, selection, selectionArgs, 192735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana sortOrder); 192835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 19296bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES: { 1930b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey qb.setTables(Tables.AGGREGATES); 1931619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1932619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesProjectionMap); 1933619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.setProjectionMap(sAggregatesProjectionMap); 1934619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 1935619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1936619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1937619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey case AGGREGATES_ID: { 1938619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long aggId = ContentUris.parseId(uri); 1939619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.setTables(Tables.AGGREGATES); 1940ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(AggregatesColumns.CONCRETE_ID + "=" + aggId + " AND "); 1941619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1942619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesProjectionMap); 19436bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov qb.setProjectionMap(sAggregatesProjectionMap); 19446bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 19456bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 19466bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 19471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case AGGREGATES_SUMMARY: { 1948619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: join into social status tables 19491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1950619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1951619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesSummaryProjectionMap); 1952619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection = assertContained(projection, Aggregates.PRIMARY_PHONE_ID); 19531f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1954bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy = aggregateIdColName; 19551f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 19561f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 19571f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 19581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case AGGREGATES_SUMMARY_ID: { 1959619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: join into social status tables 19601f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey long aggId = ContentUris.parseId(uri); 19611f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1962ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(AggregatesColumns.CONCRETE_ID + "=" + aggId + " AND "); 1963619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1964619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesSummaryProjectionMap); 1965619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection = assertContained(projection, Aggregates.PRIMARY_PHONE_ID); 19661f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1967bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy = aggregateIdColName; 19681f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 19691f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 19701f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1971ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case AGGREGATES_SUMMARY_FILTER: { 1972619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: filter query based on callingUid 1973ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1974ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1975ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 1976ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(buildAggregateLookupWhereClause(uri.getLastPathSegment())); 1977ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1978bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy = aggregateIdColName; 1979ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 1980ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1981ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 1982d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar case AGGREGATES_SUMMARY_STREQUENT_FILTER: 1983d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar case AGGREGATES_SUMMARY_STREQUENT: { 1984d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Build the first query for starred 1985d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1986d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1987d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar if (match == AGGREGATES_SUMMARY_STREQUENT_FILTER 1988d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar && uri.getPathSegments().size() > 3) { 1989d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.appendWhere(buildAggregateLookupWhereClause(uri.getLastPathSegment())); 1990d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 1991d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar final String starredQuery = qb.buildQuery(projection, Aggregates.STARRED + "=1", 1992bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar null, aggregateIdColName, null, null, 1993d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar null /* limit */); 1994d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 1995d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Build the second query for frequent 1996d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 1997d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1998d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1999d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar if (match == AGGREGATES_SUMMARY_STREQUENT_FILTER 2000d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar && uri.getPathSegments().size() > 3) { 2001d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.appendWhere(buildAggregateLookupWhereClause(uri.getLastPathSegment())); 2002d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 2003d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar final String frequentQuery = qb.buildQuery(projection, 2004d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar Aggregates.TIMES_CONTACTED + " > 0 AND (" + Aggregates.STARRED 2005d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar + " = 0 OR " + Aggregates.STARRED + " IS NULL)", 2006bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar null, aggregateIdColName, null, null, null); 2007d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 2008d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 2009d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, 2010d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar STREQUENT_ORDER_BY, STREQUENT_LIMIT); 2011d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar Cursor c = db.rawQueryWithFactory(null, query, null, 2012d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 2013d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 2014d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar if ((c != null) && !isTemporary()) { 2015d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar c.setNotificationUri(getContext().getContentResolver(), 2016d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 2017d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 2018d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar return c; 2019d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 2020d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 2021b67163a1088f09c59f324350662eb18772fac6b6Evan Millar case AGGREGATES_SUMMARY_GROUP: { 2022b67163a1088f09c59f324350662eb18772fac6b6Evan Millar qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 2023b67163a1088f09c59f324350662eb18772fac6b6Evan Millar applyAggregateRestrictionExceptions(qb); 2024b67163a1088f09c59f324350662eb18772fac6b6Evan Millar applyAggregatePrimaryRestrictionExceptions(sAggregatesSummaryProjectionMap); 2025b67163a1088f09c59f324350662eb18772fac6b6Evan Millar projection = assertContained(projection, Aggregates.PRIMARY_PHONE_ID); 2026b67163a1088f09c59f324350662eb18772fac6b6Evan Millar qb.setProjectionMap(sAggregatesSummaryProjectionMap); 2027b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (uri.getPathSegments().size() > 2) { 2028b67163a1088f09c59f324350662eb18772fac6b6Evan Millar qb.appendWhere(" AND " + sAggregatesInGroupSelect); 2029b67163a1088f09c59f324350662eb18772fac6b6Evan Millar selectionArgs = appendGroupArg(selectionArgs, uri.getLastPathSegment()); 2030b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 2031b67163a1088f09c59f324350662eb18772fac6b6Evan Millar groupBy = aggregateIdColName; 2032b67163a1088f09c59f324350662eb18772fac6b6Evan Millar break; 2033b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 2034b67163a1088f09c59f324350662eb18772fac6b6Evan Millar 20356bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES_DATA: { 2036619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long aggId = Long.parseLong(uri.getPathSegments().get(1)); 203767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_AGGREGATES_GROUPS); 20389261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setProjectionMap(sDataContactsGroupsAggregateProjectionMap); 2039619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(Contacts.AGGREGATE_ID + "=" + aggId + " AND "); 2040619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 20416bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 20426bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 204300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 2044ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES_FILTER: { 204567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_AGGREGATES); 2046ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sDataContactsAggregateProjectionMap); 2047ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 2048ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 2049ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(" AND " + buildAggregateLookupWhereClause( 2050ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar uri.getLastPathSegment())); 2051ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 2052ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 2053ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 2054ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2055ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES: { 205667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_AGGREGATES); 2057ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sDataContactsAggregateProjectionMap); 2058ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(Data.MIMETYPE + " = \"" + Phone.CONTENT_ITEM_TYPE + "\""); 2059ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 2060ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 2061ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 2062ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 206367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_AGGREGATES); 2064ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sDataContactsAggregateProjectionMap); 206567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.appendWhere(Data.MIMETYPE + " = \"" + StructuredPostal.CONTENT_ITEM_TYPE + "\""); 2066ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 2067ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 2068ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 20694f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS: { 207067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.setTables(Tables.CONTACTS); 20714f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton qb.setProjectionMap(sContactsProjectionMap); 2072619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyContactsRestrictionExceptions(qb); 20734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 20744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 20754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 20764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS_ID: { 2077619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long contactId = ContentUris.parseId(uri); 207867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.setTables(Tables.CONTACTS); 20794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton qb.setProjectionMap(sContactsProjectionMap); 2080ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(ContactsColumns.CONCRETE_ID + "=" + contactId + " AND "); 2081619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyContactsRestrictionExceptions(qb); 20824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 20834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 20844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2085a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case CONTACTS_DATA: { 2086619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long contactId = Long.parseLong(uri.getPathSegments().get(1)); 208767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_GROUPS); 20889261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setProjectionMap(sDataContactsGroupsProjectionMap); 2089619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(Data.CONTACT_ID + "=" + contactId + " AND "); 2090619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 2091a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2092a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2093a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 209428ab0f857caa92402878244d9c5ea2a59e070935Jeff Sharkey case CONTACTS_FILTER_EMAIL: { 2095619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: filter query based on callingUid 209667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_AGGREGATES); 2097e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey qb.setProjectionMap(sDataContactsProjectionMap); 20985d0f923eb4c5351ebf323cc6f19c82acff98693eJeff Sharkey qb.appendWhere(Data.MIMETYPE + "='" + CommonDataKinds.Email.CONTENT_ITEM_TYPE + "'"); 2099e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey qb.appendWhere(" AND " + CommonDataKinds.Email.DATA + "="); 2100e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey qb.appendWhereEscapeString(uri.getPathSegments().get(2)); 2101e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 2102e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 2103e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 2104e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey case DATA: { 2105035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountName = uri.getQueryParameter(Contacts.ACCOUNT_NAME); 2106035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountType = uri.getQueryParameter(Contacts.ACCOUNT_TYPE); 2107343c56b5679c58bf1835a0e219fff57beae6ecefFred Quintana if (!TextUtils.isEmpty(accountName)) { 2108035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana qb.appendWhere(Contacts.ACCOUNT_NAME + "=" 2109035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountName) + " AND " 2110035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + Contacts.ACCOUNT_TYPE + "=" 2111035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountType) + " AND "); 2112343c56b5679c58bf1835a0e219fff57beae6ecefFred Quintana } 211367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_GROUPS); 21149261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setProjectionMap(sDataGroupsProjectionMap); 2115619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 2116e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 2117e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 2118e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 21194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case DATA_ID: { 212067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_GROUPS); 21219261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setProjectionMap(sDataGroupsProjectionMap); 2122ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(DataColumns.CONCRETE_ID + "=" + ContentUris.parseId(uri) + " AND "); 2123619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 21244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 21254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 21264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2127a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 2128619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: filter query based on callingUid 2129a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton if (TextUtils.isEmpty(sortOrder)) { 2130a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // Default the sort order to something reasonable so we get consistent 2131a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // results when callers don't request an ordering 2132e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey sortOrder = Data.CONTACT_ID; 2133a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2134a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2135a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final String number = uri.getLastPathSegment(); 2136bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov OpenHelper.buildPhoneLookupQuery(qb, number); 2137a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton qb.setProjectionMap(sDataContactsProjectionMap); 2138a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2139a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2140a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2141ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 2142ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.GROUPS_JOIN_PACKAGES); 2143ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 2144ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2145ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2146ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2147ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 2148ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 2149ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.GROUPS_JOIN_PACKAGES); 2150ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 2151ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(GroupsColumns.CONCRETE_ID + "=" + groupId); 2152ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2153ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2154ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2155ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 2156ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.GROUPS_JOIN_PACKAGES_DATA_CONTACTS_AGGREGATES); 2157ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsSummaryProjectionMap); 2158ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey groupBy = GroupsColumns.CONCRETE_ID; 2159ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2160ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2161ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2162b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 2163127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS_JOIN_CONTACTS); 2164b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 2165b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 2166b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 2167b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 216831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 216931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov long aggregateId = Long.parseLong(uri.getPathSegments().get(1)); 217031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final String maxSuggestionsParam = 217131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov uri.getQueryParameter(AggregationSuggestions.MAX_SUGGESTIONS); 217231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 217331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 217431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (maxSuggestionsParam != null) { 217531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = Integer.parseInt(maxSuggestionsParam); 217631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 217731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 217831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 217931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 218031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov return mContactAggregator.queryAggregationSuggestions(aggregateId, projection, 218131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov sAggregatesProjectionMap, maxSuggestions); 218231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 218331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 21844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 2185f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.query(uri, projection, selection, selectionArgs, 2186f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov sortOrder); 21874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 21884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 21894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Perform the query and set the notification uri 21901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final Cursor c = qb.query(db, projection, selection, selectionArgs, 2191bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy, null, sortOrder, limit); 21924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 21934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 21944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 21954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 21964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 21974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 21987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 219967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey * List of package names with access to {@link Contacts#IS_RESTRICTED} data. 220067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey */ 220167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private static final String[] sAllowedPackages = new String[] { 220267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey "com.android.contacts", 220367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey "com.facebook", 220467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey }; 220567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 220667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey /** 220767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey * Check if {@link Binder#getCallingUid()} should be allowed access to 220867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey * {@link Contacts#IS_RESTRICTED} data. 220967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey */ 221067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private boolean hasRestrictedAccess() { 221167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey final PackageManager pm = getContext().getPackageManager(); 221267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey final String[] callerPackages = pm.getPackagesForUid(Binder.getCallingUid()); 221367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 221467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey // Has restricted access if caller matches any packages 221567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey for (String callerPackage : callerPackages) { 221667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey for (String allowedPackage : sAllowedPackages) { 221767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (allowedPackage.equals(callerPackage)) { 221867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey return true; 221967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 222067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 222167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 222267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey return false; 222367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 222467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 222567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey /** 2226619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Restrict selection of {@link Aggregates} to only public ones, or those 222767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey * the caller has been granted an exception to. 2228619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 2229619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private void applyAggregateRestrictionExceptions(SQLiteQueryBuilder qb) { 223067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (hasRestrictedAccess()) { 223167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.appendWhere("1"); 223267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } else { 223367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.appendWhere(AggregatesColumns.SINGLE_IS_RESTRICTED + "=0"); 2234619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2235619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2236619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2237619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 2238619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Find any exceptions that have been granted to the calling process, and 2239619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * add projections to correctly select {@link Aggregates#PRIMARY_PHONE_ID} 2240619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * and {@link Aggregates#PRIMARY_EMAIL_ID}. 2241619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 2242619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private void applyAggregatePrimaryRestrictionExceptions(HashMap<String, String> projection) { 224367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey String projectionPhone; 224467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey String projectionEmail; 224567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 224667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (hasRestrictedAccess()) { 224767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey // With restricted access, always give optimal values 224867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey projectionPhone = AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID + " AS " 224967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + Aggregates.PRIMARY_PHONE_ID; 225067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey projectionEmail = AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID + " AS " 225167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + Aggregates.PRIMARY_EMAIL_ID; 225267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } else { 225367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey // With general access, always give fallback values 225467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey projectionPhone = AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID + " AS " 225567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + Aggregates.PRIMARY_PHONE_ID; 225667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey projectionEmail = AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID + " AS " 225767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey + Aggregates.PRIMARY_EMAIL_ID; 225867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 225967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 2260619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.remove(Aggregates.PRIMARY_PHONE_ID); 2261619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.put(Aggregates.PRIMARY_PHONE_ID, projectionPhone); 2262619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2263619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.remove(Aggregates.PRIMARY_EMAIL_ID); 2264619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.put(Aggregates.PRIMARY_EMAIL_ID, projectionEmail); 2265619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2266619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2267619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 2268619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Find any exceptions that have been granted to the 2269619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link Binder#getCallingUid()}, and add a limiting clause to the given 2270619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link SQLiteQueryBuilder} to hide restricted data. 2271619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 2272619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private void applyContactsRestrictionExceptions(SQLiteQueryBuilder qb) { 227370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov qb.appendWhere(getContactsRestrictionExceptions()); 227470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 227570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 227670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov private String getContactsRestrictionExceptions() { 227767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (hasRestrictedAccess()) { 227870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov return "1"; 227970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } else { 228070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov return Contacts.IS_RESTRICTED + "=0"; 228170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 228270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 228370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 228470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov public String getContactsRestrictionExceptionAsNestedQuery(String contactIdColumn) { 228570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov if (hasRestrictedAccess()) { 228670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov return "1"; 228767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } else { 228870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov return "(SELECT " + Contacts.IS_RESTRICTED + " FROM " + Tables.CONTACTS + " WHERE " 228970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov + ContactsColumns.CONCRETE_ID + "=" + contactIdColumn + ")=0"; 2290619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2291619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2292619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2293619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 2294619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Find any exceptions that have been granted to the 2295619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link Binder#getCallingUid()}, and add a limiting clause to the given 2296619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link SQLiteQueryBuilder} to hide restricted data. 2297619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 2298e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov void applyDataRestrictionExceptions(SQLiteQueryBuilder qb) { 2299619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyContactsRestrictionExceptions(qb); 2300619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2301619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2302619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 23037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana * An implementation of EntityIterator that joins the contacts and data tables 23047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana * and consumes all the data rows for a contact in order to build the Entity for a contact. 23057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 23067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private static class ContactsEntityIterator implements EntityIterator { 23077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private final Cursor mEntityCursor; 23087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private volatile boolean mIsClosed; 23097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 23107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private static final String[] DATA_KEYS = new String[]{ 23117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data1", 23127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data2", 23137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data3", 23147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data4", 23157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data5", 23167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data6", 23177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data7", 23187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data8", 23197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data9", 232067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey "data10", 232167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey "data11", 232267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey "data12", 232367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey "data13", 232467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey "data14", 232567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey "data15"}; 23267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 23277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private static final String[] PROJECTION = new String[]{ 2328035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.ACCOUNT_NAME, 2329035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.ACCOUNT_TYPE, 2330035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.SOURCE_ID, 2331035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.VERSION, 2332035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.DIRTY, 2333035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data._ID, 233467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Contacts.Data.RES_PACKAGE, 2335035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.MIMETYPE, 2336035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA1, 2337035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA2, 2338035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA3, 2339035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA4, 2340035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA5, 2341035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA6, 2342035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA7, 2343035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA8, 2344035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA9, 2345035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA10, 234667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Contacts.Data.DATA11, 234767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Contacts.Data.DATA12, 234867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Contacts.Data.DATA13, 234967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Contacts.Data.DATA14, 235067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey Contacts.Data.DATA15, 2351035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.CONTACT_ID, 2352035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.IS_PRIMARY, 23539261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana Contacts.Data.DATA_VERSION, 23549261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana GroupMembership.GROUP_SOURCE_ID}; 2355035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana 2356035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_ACCOUNT_NAME = 0; 2357035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_ACCOUNT_TYPE = 1; 2358035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_SOURCE_ID = 2; 2359035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_VERSION = 3; 2360035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_DIRTY = 4; 2361035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_DATA_ID = 5; 236267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private static final int COLUMN_RES_PACKAGE = 6; 236367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private static final int COLUMN_MIMETYPE = 7; 236467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private static final int COLUMN_DATA1 = 8; 236567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private static final int COLUMN_CONTACT_ID = 23; 236667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private static final int COLUMN_IS_PRIMARY = 24; 236767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private static final int COLUMN_DATA_VERSION = 25; 236867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey private static final int COLUMN_GROUP_SOURCE_ID = 26; 23697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 23707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public ContactsEntityIterator(ContactsProvider2 provider, String contactsIdString, Uri uri, 23717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String selection, String[] selectionArgs, String sortOrder) { 23727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mIsClosed = false; 23737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 23747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final String updatedSortOrder = (sortOrder == null) 23757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ? Contacts.Data.CONTACT_ID 23767e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana : (Contacts.Data.CONTACT_ID + "," + sortOrder); 23777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 23787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase(); 23797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 238067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey qb.setTables(Tables.DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_GROUPS); 23819261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setProjectionMap(sDataContactsGroupsProjectionMap); 23827e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (contactsIdString != null) { 23837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana qb.appendWhere(Data.CONTACT_ID + "=" + contactsIdString); 23847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 2385035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountName = uri.getQueryParameter(Contacts.ACCOUNT_NAME); 2386035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountType = uri.getQueryParameter(Contacts.ACCOUNT_TYPE); 2387035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (!TextUtils.isEmpty(accountName)) { 2388035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana qb.appendWhere(Contacts.ACCOUNT_NAME + "=" 2389035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountName) + " AND " 2390035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + Contacts.ACCOUNT_TYPE + "=" 2391035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountType)); 2392035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 23937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs, 23947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana null, null, updatedSortOrder); 23957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mEntityCursor.moveToFirst(); 23967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 23977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 23987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public void close() { 23997e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (mIsClosed) { 24007e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("closing when already closed"); 24017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mIsClosed = true; 24037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mEntityCursor.close(); 24047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public boolean hasNext() throws RemoteException { 24077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (mIsClosed) { 24087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("calling hasNext() when the iterator is closed"); 24097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return !mEntityCursor.isAfterLast(); 24127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public Entity next() throws RemoteException { 24157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (mIsClosed) { 24167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("calling next() when the iterator is closed"); 24177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (!hasNext()) { 24197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("you may only call next() if hasNext() is true"); 24207e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteCursor c = (SQLiteCursor) mEntityCursor; 24237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final long contactId = c.getLong(COLUMN_CONTACT_ID); 24257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // we expect the cursor is already at the row we need to read from 24277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ContentValues contactValues = new ContentValues(); 2428035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana contactValues.put(Contacts.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME)); 2429035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana contactValues.put(Contacts.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE)); 24307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactValues.put(Contacts._ID, contactId); 24317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactValues.put(Contacts.DIRTY, c.getLong(COLUMN_DIRTY)); 2432f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana contactValues.put(Contacts.VERSION, c.getLong(COLUMN_VERSION)); 24337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactValues.put(Contacts.SOURCE_ID, c.getString(COLUMN_SOURCE_ID)); 24347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana Entity contact = new Entity(contactValues); 24357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24367e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // read data rows until the contact id changes 24377e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana do { 24387e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (contactId != c.getLong(COLUMN_CONTACT_ID)) { 24397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 24407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // add the data to to the contact 24427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ContentValues dataValues = new ContentValues(); 24437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(Contacts.Data._ID, c.getString(COLUMN_DATA_ID)); 244467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataValues.put(Contacts.Data.RES_PACKAGE, c.getString(COLUMN_RES_PACKAGE)); 2445f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana dataValues.put(Contacts.Data.MIMETYPE, c.getString(COLUMN_MIMETYPE)); 2446f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana dataValues.put(Contacts.Data.IS_PRIMARY, c.getString(COLUMN_IS_PRIMARY)); 2447f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana dataValues.put(Contacts.Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION)); 24489261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (!c.isNull(COLUMN_GROUP_SOURCE_ID)) { 24499261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana dataValues.put(GroupMembership.GROUP_SOURCE_ID, 24509261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana c.getString(COLUMN_GROUP_SOURCE_ID)); 24519261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 24529261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana dataValues.put(Contacts.Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION)); 24537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana for (int i = 0; i < 10; i++) { 24547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final int columnIndex = i + COLUMN_DATA1; 24557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String key = DATA_KEYS[i]; 24567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (c.isNull(columnIndex)) { 24577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // don't put anything 24587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isLong(columnIndex)) { 24597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getLong(columnIndex)); 24607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isFloat(columnIndex)) { 24617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getFloat(columnIndex)); 24627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isString(columnIndex)) { 24637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getString(columnIndex)); 24647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isBlob(columnIndex)) { 24657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getBlob(columnIndex)); 24667e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contact.addSubValue(Data.CONTENT_URI, dataValues); 24697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } while (mEntityCursor.moveToNext()); 24707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return contact; 24727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 2475a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov @Override 24767e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs, 24777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String sortOrder) { 24787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final int match = sUriMatcher.match(uri); 24797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana switch (match) { 24807e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS: 24817e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS_ID: 24827e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String contactsIdString = null; 24837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (match == CONTACTS_ID) { 24847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactsIdString = uri.getPathSegments().get(1); 24857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return new ContactsEntityIterator(this, contactsIdString, 24887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana uri, selection, selectionArgs, sortOrder); 24897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana default: 24907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new UnsupportedOperationException("Unknown uri: " + uri); 24917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 24954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 2496a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 24974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 24986bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES: return Aggregates.CONTENT_TYPE; 24996bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES_ID: return Aggregates.CONTENT_ITEM_TYPE; 25004f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS: return Contacts.CONTENT_TYPE; 25014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS_ID: return Contacts.CONTENT_ITEM_TYPE; 2502508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 25036bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 2504508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 2505b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return mOpenHelper.getDataMimeType(dataId); 250631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: return AggregationExceptions.CONTENT_TYPE; 250731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_EXCEPTION_ID: return AggregationExceptions.CONTENT_ITEM_TYPE; 250831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: return Aggregates.CONTENT_TYPE; 25094f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 2510a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton throw new UnsupportedOperationException("Unknown uri: " + uri); 25114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 25127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 2513b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov @Override 25147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 25157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throws OperationApplicationException { 25167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 25177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 25187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana db.beginTransaction(); 25197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana try { 25207e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ContentProviderResult[] results = super.applyBatch(operations); 25217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana db.setTransactionSuccessful(); 25227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return results; 25237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } finally { 25247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana db.endTransaction(); 25257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 25267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 2527c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 25283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private void setDisplayName(long contactId, String displayName) { 25293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (displayName != null) { 25303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mContactDisplayNameUpdate.bindString(1, displayName); 25313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } else { 25323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mContactDisplayNameUpdate.bindNull(1); 25333cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 25343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mContactDisplayNameUpdate.bindLong(2, contactId); 25353cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mContactDisplayNameUpdate.execute(); 25363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 25373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 2538c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /* 2539c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * Sets the given dataId record in the "data" table to primary, and resets all data records of 2540c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * the same mimetype and under the same contact to not be primary. 2541c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * 2542c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * @param dataId the id of the data record to be set to primary. 2543c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar */ 2544c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private void setIsPrimary(long dataId) { 2545c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.bindLong(1, dataId); 2546c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.bindLong(2, dataId); 2547c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.bindLong(3, dataId); 2548c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.execute(); 2549c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 2550c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 2551c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /* 2552c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * Sets the given dataId record in the "data" table to "super primary", and resets all data 2553c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * records of the same mimetype and under the same aggregate to not be "super primary". 2554c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * 2555c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * @param dataId the id of the data record to be set to primary. 2556c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar */ 2557c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private void setIsSuperPrimary(long dataId) { 2558c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.bindLong(1, dataId); 2559c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.bindLong(2, dataId); 2560c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.bindLong(3, dataId); 2561c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.execute(); 2562619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2563619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Find the parent aggregate and package for this new primary 2564619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 2565619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2566619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long aggId = -1; 2567619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean isRestricted = false; 2568619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey String mimeType = null; 2569619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2570619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey Cursor cursor = null; 2571619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey try { 257267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey cursor = db.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 257367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey DataColumns.CONCRETE_ID + "=" + dataId, null, null, null, null); 2574619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (cursor.moveToFirst()) { 257567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey aggId = cursor.getLong(DataContactsQuery.AGGREGATE_ID); 257667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey isRestricted = (cursor.getInt(DataContactsQuery.IS_RESTRICTED) == 1); 257767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey mimeType = cursor.getString(DataContactsQuery.MIMETYPE); 2578619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2579619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } finally { 2580619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (cursor != null) { 2581619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey cursor.close(); 2582619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2583619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2584619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2585619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Bypass aggregate update if no parent found, or if we don't keep track 2586619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // of super-primary for this mimetype. 2587d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov if (aggId == -1) { 2588d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return; 2589d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 2590619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2591619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean isPhone = CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mimeType); 2592619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean isEmail = CommonDataKinds.Email.CONTENT_ITEM_TYPE.equals(mimeType); 2593619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2594619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Record this value as the new primary for the parent aggregate 2595619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final ContentValues values = new ContentValues(); 2596619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (isPhone) { 2597619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID, dataId); 259867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_PHONE_IS_RESTRICTED, isRestricted); 2599619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } else if (isEmail) { 2600619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID, dataId); 260167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_IS_RESTRICTED, isRestricted); 2602619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2603619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2604619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // If this data is unrestricted, then also set as fallback 2605619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (!isRestricted && isPhone) { 2606619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID, dataId); 2607619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } else if (!isRestricted && isEmail) { 2608619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID, dataId); 2609619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2610619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2611619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Push update into aggregates table, if needed 2612619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (values.size() > 0) { 2613619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey db.update(Tables.AGGREGATES, values, Aggregates._ID + "=" + aggId, null); 2614619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2615619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2616c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 2617ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 2618ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private String buildAggregateLookupWhereClause(String filterParam) { 2619ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar StringBuilder filter = new StringBuilder(); 2620ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Tables.AGGREGATES); 2621ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append("."); 2622ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Aggregates._ID); 2623ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(" IN (SELECT "); 2624ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Contacts.AGGREGATE_ID); 2625ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(" FROM "); 2626ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Tables.CONTACTS); 2627ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(" WHERE "); 2628ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Contacts._ID); 2629d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar filter.append(" IN (SELECT contact_id FROM name_lookup WHERE normalized_name GLOB '"); 2630ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar // NOTE: Query parameters won't work here since the SQL compiler 2631ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar // needs to parse the actual string to know that it can use the 2632ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar // index to do a prefix scan. 2633d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar filter.append(NameNormalizer.normalize(filterParam) + "*"); 2634d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar filter.append("'))"); 2635ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar return filter.toString(); 2636ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 2637ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 2638b67163a1088f09c59f324350662eb18772fac6b6Evan Millar private String[] appendGroupArg(String[] selectionArgs, String arg) { 2639b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (selectionArgs == null) { 2640b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return new String[] {arg}; 2641b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } else { 2642b67163a1088f09c59f324350662eb18772fac6b6Evan Millar int newLength = selectionArgs.length + 1; 2643b67163a1088f09c59f324350662eb18772fac6b6Evan Millar String[] newSelectionArgs = new String[newLength]; 2644b67163a1088f09c59f324350662eb18772fac6b6Evan Millar System.arraycopy(selectionArgs, 0, newSelectionArgs, 0, selectionArgs.length); 2645b67163a1088f09c59f324350662eb18772fac6b6Evan Millar newSelectionArgs[newLength - 1] = arg; 2646b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return newSelectionArgs; 2647b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 2648b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 26494f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 2650