ContactsProvider2.java revision 35ed95769096bb5dd406ad7d1fcaa49a0e35a307
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 1928f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.AggregatesColumns; 2028f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.AggregationExceptionColumns; 2128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.Clauses; 2228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.ContactsColumns; 2328f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.ContactOptionsColumns; 2428f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.DataColumns; 2528f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.GroupsColumns; 2628f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.MimetypesColumns; 2728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.PhoneLookupColumns; 2828f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.Tables; 2935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport com.android.internal.content.SyncStateContentProviderHelper; 304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 31b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account; 3235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.pm.PackageManager; 334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.content.ContentProvider; 3435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.UriMatcher; 35b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.content.Context; 3635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentValues; 3735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris; 387e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport android.content.EntityIterator; 3935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.Entity; 4035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentProviderResult; 417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport android.content.OperationApplicationException; 4235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentProviderOperation; 434f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor; 44ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils; 45b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.database.sqlite.SQLiteCursor; 464f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase; 474f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder; 48c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millarimport android.database.sqlite.SQLiteStatement; 494f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri; 50619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.os.Binder; 51b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException; 52508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns; 53de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract; 546bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikovimport android.provider.Contacts.ContactMethods; 55de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Aggregates; 56b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions; 57de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds; 58de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Contacts; 59de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Data; 60ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.Groups; 611f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkeyimport android.provider.ContactsContract.Presence; 62619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.provider.ContactsContract.RestrictionExceptions; 636bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikovimport android.provider.ContactsContract.Aggregates.AggregationSuggestions; 64ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Email; 65ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.GroupMembership; 66de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.CommonDataKinds.Phone; 67ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millarimport android.provider.ContactsContract.CommonDataKinds.Postal; 684097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 69a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils; 70a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils; 7100d71133c63c882fb41729ddc3a52f66fb155374Evan Millarimport android.util.Log; 724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList; 74b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap; 754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/** 774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications 784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}. 794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */ 80035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintanapublic class ContactsProvider2 extends ContentProvider { 81b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // TODO: clean up debug tag and rename this class 82b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey private static final String TAG = "ContactsProvider ~~~~"; 834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 84619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: define broadcastreceiver to catch app uninstalls that should clear exceptions 85619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: carefully prevent all incoming nested queries; they can be gaping security holes 86619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: check for restricted flag during insert(), update(), and delete() calls 87619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 88a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 90d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final String STREQUENT_ORDER_BY = Aggregates.STARRED + " DESC, " 91d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar + Aggregates.TIMES_CONTACTED + " DESC, " 92d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar + Aggregates.DISPLAY_NAME + " ASC"; 93d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final String STREQUENT_LIMIT = 94d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar "(SELECT COUNT(1) FROM " + Tables.AGGREGATES + " WHERE " 95d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar + Aggregates.STARRED + "=1) + 25"; 96d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 976bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int AGGREGATES = 1000; 986bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int AGGREGATES_ID = 1001; 996bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int AGGREGATES_DATA = 1002; 1001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final int AGGREGATES_SUMMARY = 1003; 1011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final int AGGREGATES_SUMMARY_ID = 1004; 102ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int AGGREGATES_SUMMARY_FILTER = 1005; 103d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final int AGGREGATES_SUMMARY_STREQUENT = 1006; 104d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final int AGGREGATES_SUMMARY_STREQUENT_FILTER = 1007; 1054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1066bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int CONTACTS = 2002; 1076bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int CONTACTS_ID = 2003; 1086bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int CONTACTS_DATA = 2004; 10928ab0f857caa92402878244d9c5ea2a59e070935Jeff Sharkey private static final int CONTACTS_FILTER_EMAIL = 2005; 1104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1116bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA = 3000; 1126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA_ID = 3001; 113ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES = 3002; 114ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES_FILTER = 3003; 115ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int POSTALS = 3004; 116a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1176bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int PHONE_LOOKUP = 4000; 1186bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 119b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTIONS = 6000; 120b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTION_ID = 6001; 121b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 1221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final int PRESENCE = 7000; 1231f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final int PRESENCE_ID = 7001; 1241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 12531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int AGGREGATION_SUGGESTIONS = 8000; 12631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 127619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private static final int RESTRICTION_EXCEPTIONS = 9000; 128619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 129ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS = 10000; 130ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_ID = 10001; 131ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_SUMMARY = 10003; 132ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 13335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private static final int SYNCSTATE = 11000; 13435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 135ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private interface Projections { 136ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String[] PROJ_CONTACTS = new String[] { 137ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.CONCRETE_ID, 138ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 139ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 140ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String[] PROJ_DATA_CONTACTS = new String[] { 141ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.CONCRETE_ID, 142ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey DataColumns.CONCRETE_ID, 143ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Contacts.AGGREGATE_ID, 144ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.PACKAGE_ID, 145ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Contacts.IS_RESTRICTED, 146ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Data.MIMETYPE, 147ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 148ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 149ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_CONTACT_ID = 0; 150ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_DATA_ID = 1; 151ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_AGGREGATE_ID = 2; 152ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_PACKAGE_ID = 3; 153ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_IS_RESTRICTED = 4; 154ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_MIMETYPE = 5; 155ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 156ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String[] PROJ_DATA_AGGREGATES = new String[] { 157ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.CONCRETE_ID, 158ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey DataColumns.CONCRETE_ID, 159ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.CONCRETE_ID, 160ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey MimetypesColumns.CONCRETE_ID, 161ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Phone.NUMBER, 162ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Email.DATA, 163ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID, 164ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID, 165ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID, 166ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID, 167ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 168ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 169ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_MIMETYPE_ID = 3; 170ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_PHONE_NUMBER = 4; 171ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_EMAIL_DATA = 5; 172ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_OPTIMAL_PHONE_ID = 6; 173ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_FALLBACK_PHONE_ID = 7; 174ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_OPTIMAL_EMAIL_ID = 8; 175ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_FALLBACK_EMAIL_ID = 9; 17680c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 177ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1781f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 17931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /** Default for the maximum number of returned aggregation suggestions. */ 18031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int DEFAULT_MAX_SUGGESTIONS = 5; 18131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1826bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** Contains just the contacts columns */ 1836bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final HashMap<String, String> sAggregatesProjectionMap; 18400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar /** Contains the aggregate columns along with primary phone */ 1851f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final HashMap<String, String> sAggregatesSummaryProjectionMap; 186de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar /** Contains the data, contacts, and aggregate columns, for joined tables. */ 187de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar private static final HashMap<String, String> sDataContactsAggregateProjectionMap; 188a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** Contains just the contacts columns */ 1894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton private static final HashMap<String, String> sContactsProjectionMap; 190a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** Contains just the data columns */ 1914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton private static final HashMap<String, String> sDataProjectionMap; 192a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** Contains the data and contacts columns, for joined tables */ 193a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton private static final HashMap<String, String> sDataContactsProjectionMap; 194ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains the just the {@link Groups} columns */ 195ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final HashMap<String, String> sGroupsProjectionMap; 196ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains {@link Groups} columns along with summary details */ 197ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final HashMap<String, String> sGroupsSummaryProjectionMap; 198b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov /** Contains the just the agg_exceptions columns */ 199b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final HashMap<String, String> sAggregationExceptionsProjectionMap; 200619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** Contains the just the {@link RestrictionExceptions} columns */ 201619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private static final HashMap<String, String> sRestrictionExceptionsProjectionMap; 2027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 203c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns the contact id associated with a data record. */ 204c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedContactIdSelect; 205c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns the mimetype id associated with a data record. */ 206c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedMimetypeSelect; 207c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns the aggregate id associated with a contact record. */ 208c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedAggregateIdSelect; 209c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns a list of contact ids associated with an aggregate record. */ 210c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedContactIdListSelect; 211c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql where statement used to match all the data records that need to be updated when a new 212c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * "primary" is selected.*/ 213c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sSetPrimaryWhere; 214c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql where statement used to match all the data records that need to be updated when a new 215c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * "super primary" is selected.*/ 216c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sSetSuperPrimaryWhere; 217c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Precompiled sql statement for setting a data record to the primary. */ 218c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private SQLiteStatement mSetPrimaryStatement; 219c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Precomipled sql statement for setting a data record to the super primary. */ 220c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private SQLiteStatement mSetSuperPrimaryStatement; 221a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 2221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final String GTALK_PROTOCOL_STRING = ContactMethods 2231f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey .encodePredefinedImProtocol(ContactMethods.PROTOCOL_GOOGLE_TALK); 2241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 2264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 227a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 2286bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates", AGGREGATES); 2296bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates/#", AGGREGATES_ID); 2306bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates/#/data", AGGREGATES_DATA); 2311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary", AGGREGATES_SUMMARY); 2321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/#", AGGREGATES_SUMMARY_ID); 233ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/filter/*", 234ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar AGGREGATES_SUMMARY_FILTER); 235d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/strequent/", 236d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar AGGREGATES_SUMMARY_STREQUENT); 237d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/strequent/filter/*", 238d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar AGGREGATES_SUMMARY_STREQUENT_FILTER); 23931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates/#/suggestions", 24031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 2414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 2424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 243a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_DATA); 244b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter_email/*", 245b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov CONTACTS_FILTER_EMAIL); 246b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 2474f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 2484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 249ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 250ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 251ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 2521f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 253ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 254ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 255ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 256ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 25735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 25835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 259a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 260b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 261b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 262b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 263b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 2644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 265bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "presence", PRESENCE); 266bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "presence/#", PRESENCE_ID); 2671f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 268619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "restriction_exceptions", RESTRICTION_EXCEPTIONS); 269619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 270fec4e13316f2731d84394e5fa2f93af3febdc20cEvan Millar HashMap<String, String> columns; 2714f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2726bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov // Aggregates projection map 2736bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns = new HashMap<String, String>(); 27400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar columns.put(Aggregates._ID, "aggregates._id AS _id"); 2756bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns.put(Aggregates.DISPLAY_NAME, Aggregates.DISPLAY_NAME); 2766bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns.put(Aggregates.LAST_TIME_CONTACTED, Aggregates.LAST_TIME_CONTACTED); 277d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar columns.put(Aggregates.TIMES_CONTACTED, Aggregates.TIMES_CONTACTED); 2786bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns.put(Aggregates.STARRED, Aggregates.STARRED); 279ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Aggregates.IN_VISIBLE_GROUP, Aggregates.IN_VISIBLE_GROUP); 280de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar columns.put(Aggregates.PRIMARY_PHONE_ID, Aggregates.PRIMARY_PHONE_ID); 281c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar columns.put(Aggregates.PRIMARY_EMAIL_ID, Aggregates.PRIMARY_EMAIL_ID); 282d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov columns.put(Aggregates.CUSTOM_RINGTONE, Aggregates.CUSTOM_RINGTONE); 283d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov columns.put(Aggregates.SEND_TO_VOICEMAIL, Aggregates.SEND_TO_VOICEMAIL); 284619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID, 285619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID); 286619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID, 287619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID); 2886bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov sAggregatesProjectionMap = columns; 2896bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 2901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // Aggregates primaries projection map. The overall presence status is 2911f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // the most-present value, as indicated by the largest value. 2921f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey columns = new HashMap<String, String>(); 2931f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey columns.putAll(sAggregatesProjectionMap); 29400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar columns.put(CommonDataKinds.Phone.TYPE, CommonDataKinds.Phone.TYPE); 29500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar columns.put(CommonDataKinds.Phone.LABEL, CommonDataKinds.Phone.LABEL); 29600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar columns.put(CommonDataKinds.Phone.NUMBER, CommonDataKinds.Phone.NUMBER); 297bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar columns.put(Presence.PRESENCE_STATUS, "MAX(" + Presence.PRESENCE_STATUS + ")"); 2981f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey sAggregatesSummaryProjectionMap = columns; 29900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 3004f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts projection map 3014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns = new HashMap<String, String>(); 3024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns.put(Contacts._ID, "contacts._id AS _id"); 303619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(Contacts.PACKAGE, Contacts.PACKAGE); 3046bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns.put(Contacts.AGGREGATE_ID, Contacts.AGGREGATE_ID); 305035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana columns.put(Contacts.ACCOUNT_NAME, Contacts.ACCOUNT_NAME); 306035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana columns.put(Contacts.ACCOUNT_TYPE, Contacts.ACCOUNT_TYPE); 3077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Contacts.SOURCE_ID, Contacts.SOURCE_ID); 3087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Contacts.VERSION, Contacts.VERSION); 3097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Contacts.DIRTY, Contacts.DIRTY); 3104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton sContactsProjectionMap = columns; 3114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 3124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Data projection map 3134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns = new HashMap<String, String>(); 3144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns.put(Data._ID, "data._id AS _id"); 3154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns.put(Data.CONTACT_ID, Data.CONTACT_ID); 316508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey columns.put(Data.MIMETYPE, Data.MIMETYPE); 317c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar columns.put(Data.IS_PRIMARY, Data.IS_PRIMARY); 318c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar columns.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY); 319f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana columns.put(Data.DATA_VERSION, Data.DATA_VERSION); 3207e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA1, "data.data1 as data1"); 3217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA2, "data.data2 as data2"); 3227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA3, "data.data3 as data3"); 3237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA4, "data.data4 as data4"); 3247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA5, "data.data5 as data5"); 3257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA6, "data.data6 as data6"); 3267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA7, "data.data7 as data7"); 3277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA8, "data.data8 as data8"); 3287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA9, "data.data9 as data9"); 3297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA10, "data.data10 as data10"); 330d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Mappings used for backwards compatibility. 331d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar columns.put("number", Phone.NUMBER); 3324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton sDataProjectionMap = columns; 333a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 334a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // Data and contacts projection map for joins. _id comes from the data table 335a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton columns = new HashMap<String, String>(); 336a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton columns.putAll(sContactsProjectionMap); 337a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton columns.putAll(sDataProjectionMap); // _id will be replaced with the one from data 338ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Data.CONTACT_ID, DataColumns.CONCRETE_CONTACT_ID); 339a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton sDataContactsProjectionMap = columns; 3407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 341de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar // Data and contacts projection map for joins. _id comes from the data table 342de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar columns = new HashMap<String, String>(); 343de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar columns.putAll(sAggregatesProjectionMap); 3447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.putAll(sContactsProjectionMap); // 345de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar columns.putAll(sDataProjectionMap); // _id will be replaced with the one from data 346ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Data.CONTACT_ID, DataColumns.CONCRETE_CONTACT_ID); 347de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar sDataContactsAggregateProjectionMap = columns; 348c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 349ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Groups projection map 350ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns = new HashMap<String, String>(); 351ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups._ID, "groups._id AS _id"); 352035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana columns.put(Groups.ACCOUNT_NAME, Groups.ACCOUNT_NAME); 353035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana columns.put(Groups.ACCOUNT_TYPE, Groups.ACCOUNT_TYPE); 354ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.PACKAGE, Groups.PACKAGE); 355ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.PACKAGE_ID, GroupsColumns.CONCRETE_PACKAGE_ID); 356ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.TITLE, Groups.TITLE); 357ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.TITLE_RESOURCE, Groups.TITLE_RESOURCE); 358ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.GROUP_VISIBLE, Groups.GROUP_VISIBLE); 359ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey sGroupsProjectionMap = columns; 360ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 361ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Contacts and groups projection map 362ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns = new HashMap<String, String>(); 363ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.putAll(sGroupsProjectionMap); 364ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 365ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.SUMMARY_COUNT, "(SELECT COUNT(DISTINCT " + AggregatesColumns.CONCRETE_ID 366ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + ") FROM " + Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES + " WHERE " 367ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP 368ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + ") AS " + Groups.SUMMARY_COUNT); 369ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 370ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.SUMMARY_WITH_PHONES, "(SELECT COUNT(DISTINCT " 371ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + AggregatesColumns.CONCRETE_ID + ") FROM " 372ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES + " WHERE " 373ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP 374ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + " AND " + Clauses.HAS_PRIMARY_PHONE + ") AS " + Groups.SUMMARY_WITH_PHONES); 375ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 376ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey sGroupsSummaryProjectionMap = columns; 377ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 378b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov // Aggregate exception projection map 379b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov columns = new HashMap<String, String>(); 380b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov columns.put(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id AS _id"); 381b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov columns.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE); 382127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov columns.put(AggregationExceptions.AGGREGATE_ID, 383127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov "contacts1." + Contacts.AGGREGATE_ID + " AS " + AggregationExceptions.AGGREGATE_ID); 384127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov columns.put(AggregationExceptions.CONTACT_ID, AggregationExceptionColumns.CONTACT_ID2); 385b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov sAggregationExceptionsProjectionMap = columns; 386b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 387619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Restriction exception projection map 388619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns = new HashMap<String, String>(); 389619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(RestrictionExceptions.PACKAGE_PROVIDER, RestrictionExceptions.PACKAGE_PROVIDER); 390619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(RestrictionExceptions.PACKAGE_CLIENT, RestrictionExceptions.PACKAGE_CLIENT); 391619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(RestrictionExceptions.ALLOW_ACCESS, "1"); // Access granted if row returned 392619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey sRestrictionExceptionsProjectionMap = columns; 393619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 394c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedContactIdSelect = "SELECT " + Data.CONTACT_ID + " FROM " + Tables.DATA + " WHERE " 395c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + Data._ID + "=?"; 396c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedMimetypeSelect = "SELECT " + DataColumns.MIMETYPE_ID + " FROM " + Tables.DATA 397c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + " WHERE " + Data._ID + "=?"; 398c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedAggregateIdSelect = "SELECT " + Contacts.AGGREGATE_ID + " FROM " + Tables.CONTACTS 399c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + " WHERE " + Contacts._ID + "=(" + sNestedContactIdSelect + ")"; 400c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedContactIdListSelect = "SELECT " + Contacts._ID + " FROM " + Tables.CONTACTS 401c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + " WHERE " + Contacts.AGGREGATE_ID + "=(" + sNestedAggregateIdSelect + ")"; 402c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sSetPrimaryWhere = Data.CONTACT_ID + "=(" + sNestedContactIdSelect + ") AND " 403c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + DataColumns.MIMETYPE_ID + "=(" + sNestedMimetypeSelect + ")"; 404c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sSetSuperPrimaryWhere = Data.CONTACT_ID + " IN (" + sNestedContactIdListSelect + ") AND " 405c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + DataColumns.MIMETYPE_ID + "=(" + sNestedMimetypeSelect + ")"; 4064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 4074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 40853056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov private final ContactAggregationScheduler mAggregationScheduler; 4094f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton private OpenHelper mOpenHelper; 41031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 411a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov private ContactAggregator mContactAggregator; 4124097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 413a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 414a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public ContactsProvider2() { 41553056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov this(new ContactAggregationScheduler()); 416a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 417a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 418a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 419a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Constructor for testing. 420a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 42153056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov /* package */ ContactsProvider2(ContactAggregationScheduler scheduler) { 42253056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov mAggregationScheduler = scheduler; 423a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 4244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 4254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 4264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 427b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey final Context context = getContext(); 42835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 42931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov mOpenHelper = getOpenHelper(context); 4301f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 4314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 43253056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov mContactAggregator = new ContactAggregator(context, mOpenHelper, mAggregationScheduler); 433a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 434c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement = db.compileStatement( 435c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar "UPDATE " + Tables.DATA + " SET " + Data.IS_PRIMARY 436c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + "=(_id=?) WHERE " + sSetPrimaryWhere); 437c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement = db.compileStatement( 438c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar "UPDATE " + Tables.DATA + " SET " + Data.IS_SUPER_PRIMARY 439c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + "=(_id=?) WHERE " + sSetSuperPrimaryWhere); 440a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 44128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar mNameSplitter = new NameSplitter( 44228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_name_prefixes), 44328f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_last_name_prefixes), 44428f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_name_suffixes), 44528f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_name_conjunctions)); 4464097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 4471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return (db != null); 4484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 4494f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 45031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /* Visible for testing */ 45131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov protected OpenHelper getOpenHelper(final Context context) { 45231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov return OpenHelper.getInstance(context); 45331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 45431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 455a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov @Override 456a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov protected void finalize() throws Throwable { 457a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov if (mContactAggregator != null) { 458a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov mContactAggregator.quit(); 459a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 460a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 461a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov super.finalize(); 462a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 463a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 464a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 465a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 466a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 467a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /* package */ void wipeData() { 468a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov mOpenHelper.wipeData(); 469a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 470a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 471a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 472a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Called when a change has been made. 473a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 474a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param uri the uri that the change was made to 475a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 476a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton private void onChange(Uri uri) { 477a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null); 478a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 479a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 4804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 4814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean isTemporary() { 4824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return false; 4834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 4844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 4854f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 4864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Uri insert(Uri uri, ContentValues values) { 487a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 488a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 48935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 490a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 49135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 49235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana id = mOpenHelper.getSyncState().insert(mOpenHelper.getWritableDatabase(), values); 49335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 49435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4956bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES: { 4966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov id = insertAggregate(values); 4976bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 4986bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 4996bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 500a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case CONTACTS: { 501f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana final Account account = readAccountFromQueryParams(uri); 502f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana id = insertContact(values, account); 503a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 504a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 505a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 506a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case CONTACTS_DATA: { 507a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton values.put(Data.CONTACT_ID, uri.getPathSegments().get(1)); 508035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana id = insertData(values); 509a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 510a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 511a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 512a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case DATA: { 513035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana id = insertData(values); 514a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 515a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 516a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 517ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 518ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final Account account = readAccountFromQueryParams(uri); 519ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey id = insertGroup(values, account); 520ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 521ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 522ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5231f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case PRESENCE: { 5241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey id = insertPresence(values); 5251f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 5261f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 5271f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 528a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 529508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey throw new UnsupportedOperationException("Unknown uri: " + uri); 530a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 531a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 5337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 5347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 5357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 5367e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final Uri result = ContentUris.withAppendedId(uri, id); 537a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton onChange(result); 538a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return result; 539a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 540a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 541a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 542035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * If account is non-null then store it in the values. If the account is already 543035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * specified in the values then it must be consistent with the account, if it is non-null. 544035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * @param values the ContentValues to read from and update 545035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * @param account the explicitly provided Account 546035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * @return false if the accounts are inconsistent 5477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 548035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private boolean resolveAccount(ContentValues values, Account account) { 549035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana // If either is specified then both must be specified. 550035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountName = values.getAsString(Contacts.ACCOUNT_NAME); 551035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountType = values.getAsString(Contacts.ACCOUNT_TYPE); 552035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (!TextUtils.isEmpty(accountName) || !TextUtils.isEmpty(accountType)) { 553035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final Account valuesAccount = new Account(accountName, accountType); 554035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (account != null && !valuesAccount.equals(account)) { 555035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana return false; 556035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 557035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana account = valuesAccount; 558035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 559035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (account != null) { 560035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana values.put(Contacts.ACCOUNT_NAME, account.mName); 561035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana values.put(Contacts.ACCOUNT_TYPE, account.mType); 562035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 563035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana return true; 5647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 5657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 5667e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 5676bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * Inserts an item in the aggregates table 5686bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 5696bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 5706bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 5716bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 5726bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private long insertAggregate(ContentValues values) { 573a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov throw new UnsupportedOperationException("Aggregates are created automatically"); 5746bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 5756bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 5766bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 577a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the contacts table 578a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 579a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 580f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana * @param account the account this contact should be associated with. may be null. 581a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 582a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 583f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana private long insertContact(ContentValues values, Account account) { 5846bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /* 5856bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * The contact record is inserted in the contacts table, but it needs to 5866bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * be processed by the aggregator before it will be returned by the 5876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * "aggregates" queries. 5886bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 589a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 5906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 591a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov ContentValues overriddenValues = new ContentValues(values); 592a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov overriddenValues.putNull(Contacts.AGGREGATE_ID); 593f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana if (!resolveAccount(overriddenValues, account)) { 5947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return -1; 5957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 5967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 597619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Replace package with internal mapping 598619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String packageName = overriddenValues.getAsString(Contacts.PACKAGE); 599619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey overriddenValues.put(ContactsColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName)); 600619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey overriddenValues.remove(Contacts.PACKAGE); 601619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 602a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov long rowId = db.insert(Tables.CONTACTS, Contacts.AGGREGATE_ID, overriddenValues); 603a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 604a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov mContactAggregator.schedule(); 605a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 606a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov return rowId; 607a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 608a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 609a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 610a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 611a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 612a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 613a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 614a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 615035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private long insertData(ContentValues values) { 616a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov boolean success = false; 617a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 618a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 619a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 620a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton db.beginTransaction(); 621a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton try { 622a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov long contactId = values.getAsLong(Data.CONTACT_ID); 623a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 624619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Replace mimetype with internal mapping 625508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final String mimeType = values.getAsString(Data.MIMETYPE); 626b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey values.put(DataColumns.MIMETYPE_ID, mOpenHelper.getMimeTypeId(mimeType)); 627508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey values.remove(Data.MIMETYPE); 628508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 6294097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) { 6304097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov parseStructuredName(values); 6314097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov } 6324097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 633508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey // Insert the data row itself 634b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey id = db.insert(Tables.DATA, Data.DATA1, values); 635508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 636a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // If it's a phone number add the normalized version to the lookup table 6374097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) { 638508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final ContentValues phoneValues = new ContentValues(); 639508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final String number = values.getAsString(Phone.NUMBER); 640508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, 641508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey PhoneNumberUtils.getStrippedReversed(number)); 642508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey phoneValues.put(PhoneLookupColumns.DATA_ID, id); 643a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov phoneValues.put(PhoneLookupColumns.CONTACT_ID, contactId); 644b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.insert(Tables.PHONE_LOOKUP, null, phoneValues); 645a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 646a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 6476bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov mContactAggregator.markContactForAggregation(contactId); 648a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 649a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton db.setTransactionSuccessful(); 650a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov success = true; 651a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } finally { 652a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton db.endTransaction(); 653a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 654a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 655a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov if (success) { 656a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov mContactAggregator.schedule(); 657a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 658a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 659a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 6604f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 6614f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 662a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 663ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Delete the given {@link Data} row, fixing up any {@link Aggregates} 664ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * primaries that reference it. 665ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 666ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private int deleteData(long dataId) { 667ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 668ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 669ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long mimePhone = mOpenHelper.getMimeTypeId(Phone.CONTENT_ITEM_TYPE); 670ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long mimeEmail = mOpenHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE); 671ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 672ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Check to see if the data about to be deleted was a super-primary on 673ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // the parent aggregate, and set flags to fix-up once deleted. 674ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long aggId = -1; 675ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long mimeId = -1; 676ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String dataRaw = null; 677ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey boolean fixOptimal = false; 678ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey boolean fixFallback = false; 679ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 680ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Cursor cursor = null; 681ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey try { 682ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = db.query(Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES, 683ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Projections.PROJ_DATA_AGGREGATES, DataColumns.CONCRETE_ID + "=" + dataId, null, 684ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey null, null, null); 685ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (cursor.moveToFirst()) { 686ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey aggId = cursor.getLong(Projections.COL_AGGREGATE_ID); 687ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mimeId = cursor.getLong(Projections.COL_MIMETYPE_ID); 688ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 689ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey dataRaw = cursor.getString(Projections.COL_PHONE_NUMBER); 690ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey fixOptimal = (cursor.getLong(Projections.COL_OPTIMAL_PHONE_ID) == dataId); 691ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey fixFallback = (cursor.getLong(Projections.COL_FALLBACK_PHONE_ID) == dataId); 692ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 693ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey dataRaw = cursor.getString(Projections.COL_EMAIL_DATA); 694ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey fixOptimal = (cursor.getLong(Projections.COL_OPTIMAL_EMAIL_ID) == dataId); 695ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey fixFallback = (cursor.getLong(Projections.COL_FALLBACK_EMAIL_ID) == dataId); 696ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 697ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 698ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } finally { 699ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (cursor != null) { 700ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor.close(); 701ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = null; 702ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 703ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 704ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 705ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Delete the requested data item. 706ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey int dataDeleted = db.delete(Tables.DATA, Data._ID + "=" + dataId, null); 707ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 708ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Fix-up any super-primary values that are now invalid. 709ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (fixOptimal || fixFallback) { 710ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final ContentValues values = new ContentValues(); 711ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final StringBuilder scoreClause = new StringBuilder(); 712ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 713ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final String SCORE = "score"; 714ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 715ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Build scoring clause that will first pick data items under the 716ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // same aggregate that have identical values, otherwise fall back to 717ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // normal primary scoring from the member contacts. 718ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append("(CASE WHEN "); 719ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 720ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append(Phone.NUMBER); 721ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 722ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append(Email.DATA); 723ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 724ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append("="); 725ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey DatabaseUtils.appendEscapedSQLString(scoreClause, dataRaw); 726ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append(" THEN 2 ELSE " + Data.IS_PRIMARY + " END) AS " + SCORE); 727ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 728ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final String[] PROJ_PRIMARY = new String[] { 729ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey DataColumns.CONCRETE_ID, 730ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Contacts.IS_RESTRICTED, 731ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.PACKAGE_ID, 732ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.toString(), 733ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 734ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 735ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final int COL_DATA_ID = 0; 736ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final int COL_IS_RESTRICTED = 1; 737ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final int COL_PACKAGE_ID = 2; 738ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final int COL_SCORE = 3; 739ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 740ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = db.query(Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES, PROJ_PRIMARY, 741ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.CONCRETE_ID + "=" + aggId + " AND " + DataColumns.MIMETYPE_ID 742ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "=" + mimeId, null, null, null, SCORE); 743ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 744ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (fixOptimal) { 745ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String colId = null; 746ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String colPackageId = null; 747ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 748ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID; 749ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colPackageId = AggregatesColumns.OPTIMAL_PRIMARY_PHONE_PACKAGE_ID; 750ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 751ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID; 752ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colPackageId = AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_PACKAGE_ID; 753ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 754ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 755ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Start by replacing with null, since fixOptimal told us that 756ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // the previous aggregate values are bad. 757ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.putNull(colId); 758ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.putNull(colPackageId); 759ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 760ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // When finding a new optimal primary, we only care about the 761ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // highest scoring value, regardless of source. 762ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (cursor.moveToFirst()) { 763ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long newOptimal = cursor.getLong(COL_DATA_ID); 764ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long newOptimalPackage = cursor.getLong(COL_PACKAGE_ID); 765ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 766ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (newOptimal != 0) { 767ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.put(colId, newOptimal); 768ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 769ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (newOptimalPackage != 0) { 770ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.put(colPackageId, newOptimalPackage); 771ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 772ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 773ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 774ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 775ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (fixFallback) { 776ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String colId = null; 777ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 778ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID; 779ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 780ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID; 781ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 782ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 783ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Start by replacing with null, since fixFallback told us that 784ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // the previous aggregate values are bad. 785ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.putNull(colId); 786ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 787ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // The best fallback value is the highest scoring data item that 788ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // hasn't been restricted. 789ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor.moveToPosition(-1); 790ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey while (cursor.moveToNext()) { 791ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final boolean isRestricted = (cursor.getInt(COL_IS_RESTRICTED) == 1); 792ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (!isRestricted) { 793ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.put(colId, cursor.getLong(COL_DATA_ID)); 794ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 795ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 796ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 797ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 798ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 799ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Push through any aggregate updates we have 800ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (values.size() > 0) { 801ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey db.update(Tables.AGGREGATES, values, AggregatesColumns.CONCRETE_ID + "=" + aggId, 802ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey null); 803ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 804ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 805ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 806ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return dataDeleted; 807ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 808ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 809ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 8104097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov * Parse the supplied display name, but only if the incoming values do not already contain 8114097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov * structured name parts. 8124097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov */ 8134097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private void parseStructuredName(ContentValues values) { 8144097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov final String fullName = values.getAsString(StructuredName.DISPLAY_NAME); 8154097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov if (TextUtils.isEmpty(fullName) 8164097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov || !TextUtils.isEmpty(values.getAsString(StructuredName.PREFIX)) 8174097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov || !TextUtils.isEmpty(values.getAsString(StructuredName.GIVEN_NAME)) 8184097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov || !TextUtils.isEmpty(values.getAsString(StructuredName.MIDDLE_NAME)) 8194097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov || !TextUtils.isEmpty(values.getAsString(StructuredName.FAMILY_NAME)) 8204097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov || !TextUtils.isEmpty(values.getAsString(StructuredName.SUFFIX))) { 8214097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov return; 8224097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov } 8234097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 8244097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov NameSplitter.Name name = new NameSplitter.Name(); 8254097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov mNameSplitter.split(name, fullName); 8264097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 8274097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov values.put(StructuredName.PREFIX, name.getPrefix()); 8284097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov values.put(StructuredName.GIVEN_NAME, name.getGivenNames()); 8294097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov values.put(StructuredName.MIDDLE_NAME, name.getMiddleName()); 8304097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov values.put(StructuredName.FAMILY_NAME, name.getFamilyName()); 8314097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov values.put(StructuredName.SUFFIX, name.getSuffix()); 8324097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov } 8334097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 8344097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov /** 835ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 836ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 837ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private long insertGroup(ContentValues values, Account account) { 838ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 839ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 840ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContentValues overriddenValues = new ContentValues(values); 841ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (!resolveAccount(overriddenValues, account)) { 842ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return -1; 843ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 844ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 845ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 846ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final String packageName = overriddenValues.getAsString(Groups.PACKAGE); 847ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey overriddenValues.put(Groups.PACKAGE_ID, mOpenHelper.getPackageId(packageName)); 848ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey overriddenValues.remove(Groups.PACKAGE); 849ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 850ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return db.insert(Tables.GROUPS, Groups.TITLE, overriddenValues); 851ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 852ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 853ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 8541f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey * Inserts a presence update. 8551f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 8561f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private long insertPresence(ContentValues values) { 8571f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 8581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final String handle = values.getAsString(Presence.IM_HANDLE); 8591f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final String protocol = values.getAsString(Presence.IM_PROTOCOL); 8601f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (TextUtils.isEmpty(handle) || TextUtils.isEmpty(protocol)) { 8611f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey throw new IllegalArgumentException("IM_PROTOCOL and IM_HANDLE are required"); 8621f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 8631f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 8641f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // TODO: generalize to allow other providers to match against email 8651f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey boolean matchEmail = GTALK_PROTOCOL_STRING.equals(protocol); 8661f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 8671f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String selection; 8681f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String[] selectionArgs; 8691f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (matchEmail) { 8701f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey selection = "(" + Clauses.WHERE_IM_MATCHES + ") OR (" + Clauses.WHERE_EMAIL_MATCHES + ")"; 8711f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey selectionArgs = new String[] { protocol, handle, handle }; 8721f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 8731f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey selection = Clauses.WHERE_IM_MATCHES; 8741f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey selectionArgs = new String[] { protocol, handle }; 8751f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 8761f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 8771f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey long dataId = -1; 8781f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey long aggId = -1; 8791f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 8801f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 881ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = db.query(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES, 882ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Projections.PROJ_DATA_CONTACTS, selection, selectionArgs, null, null, null); 8831f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 884ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey dataId = cursor.getLong(Projections.COL_DATA_ID); 885ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey aggId = cursor.getLong(Projections.COL_AGGREGATE_ID); 8861f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 8871f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 8881f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 8891f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 8901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 89131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 89231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 89331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 8941f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 8951f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 8961f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey values.put(Presence.DATA_ID, dataId); 8971f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey values.put(Presence.AGGREGATE_ID, aggId); 8981f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 8991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // Insert the presence update 9001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey long presenceId = db.replace(Tables.PRESENCE, null, values); 9011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return presenceId; 9021f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 9031f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 9044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 9054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public int delete(Uri uri, String selection, String[] selectionArgs) { 906508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 907508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 908508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 90935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 91035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana return mOpenHelper.getSyncState().delete(db, selection, selectionArgs); 91135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 9126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES_ID: { 9136bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov long aggregateId = ContentUris.parseId(uri); 9146bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 9156bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov // Remove references to the aggregate first 9166bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov ContentValues values = new ContentValues(); 9176bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov values.putNull(Contacts.AGGREGATE_ID); 918b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.update(Tables.CONTACTS, values, Contacts.AGGREGATE_ID + "=" + aggregateId, null); 9196bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 920b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return db.delete(Tables.AGGREGATES, BaseColumns._ID + "=" + aggregateId, null); 9216bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 9226bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 923508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case CONTACTS_ID: { 924508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long contactId = ContentUris.parseId(uri); 925b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey int contactsDeleted = db.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null); 926b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey int dataDeleted = db.delete(Tables.DATA, Data.CONTACT_ID + "=" + contactId, null); 927508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey return contactsDeleted + dataDeleted; 928508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 929508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 930508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: { 931508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 932ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return deleteData(dataId); 933ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 934ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 935ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 936ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 937ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long groupMembershipMimetypeId = mOpenHelper 938ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 939ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey int groupsDeleted = db.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 940ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey int dataDeleted = db.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 941ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 942ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + groupId, null); 943ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mOpenHelper.updateAllVisible(); 944ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return groupsDeleted + dataDeleted; 945508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 946508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 9471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case PRESENCE: { 9481f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return db.delete(Tables.PRESENCE, null, null); 9491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 9501f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 951508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey default: 952508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey throw new UnsupportedOperationException("Unknown uri: " + uri); 953508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 9544f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 9554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 956f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana private static Account readAccountFromQueryParams(Uri uri) { 957035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String name = uri.getQueryParameter(Contacts.ACCOUNT_NAME); 958035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String type = uri.getQueryParameter(Contacts.ACCOUNT_TYPE); 959f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana if (TextUtils.isEmpty(name) || TextUtils.isEmpty(type)) { 960f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana return null; 961f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana } 962f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana return new Account(name, type); 963f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana } 964f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana 965ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 9664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 9674f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 96800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 96935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 97000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 97100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 97200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 97335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 97435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana return mOpenHelper.getSyncState().update(db, values, selection, selectionArgs); 97535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 976c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar // TODO(emillar): We will want to disallow editing the aggregates table at some point. 97700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar case AGGREGATES: { 97800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar count = db.update(Tables.AGGREGATES, values, selection, selectionArgs); 97900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 98000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 98100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 98200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar case AGGREGATES_ID: { 983d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov count = updateAggregateData(db, ContentUris.parseId(uri), values); 984c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 985c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 986c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 987c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar case DATA_ID: { 988c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar boolean containsIsSuperPrimary = values.containsKey(Data.IS_SUPER_PRIMARY); 989c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar boolean containsIsPrimary = values.containsKey(Data.IS_PRIMARY); 990c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar final long id = ContentUris.parseId(uri); 991c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 992c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar // Remove primary or super primary values being set to 0. This is disallowed by the 993c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar // content provider. 9948b341f8ea85257c5f7103863405e0273921e16bcEvan Millar if (containsIsSuperPrimary && values.getAsInteger(Data.IS_SUPER_PRIMARY) == 0) { 995c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar containsIsSuperPrimary = false; 996c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar values.remove(Data.IS_SUPER_PRIMARY); 997c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 9988b341f8ea85257c5f7103863405e0273921e16bcEvan Millar if (containsIsPrimary && values.getAsInteger(Data.IS_PRIMARY) == 0) { 999c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar containsIsPrimary = false; 1000c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar values.remove(Data.IS_PRIMARY); 1001c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 1002c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1003c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar if (containsIsSuperPrimary) { 1004c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar setIsSuperPrimary(id); 1005c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar setIsPrimary(id); 1006c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1007c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar // Now that we've taken care of setting these, remove them from "values". 1008c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar values.remove(Data.IS_SUPER_PRIMARY); 1009c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar if (containsIsPrimary) { 1010c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar values.remove(Data.IS_PRIMARY); 1011c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 1012c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } else if (containsIsPrimary) { 1013c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar setIsPrimary(id); 1014c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1015c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar // Now that we've taken care of setting this, remove it from "values". 1016c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar values.remove(Data.IS_PRIMARY); 1017c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 1018c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1019c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar if (values.size() > 0) { 1020c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar String selectionWithId = (Data._ID + " = " + ContentUris.parseId(uri) + " ") 1021f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + (selection == null ? "" : " AND " + selection); 1022c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar count = db.update(Tables.DATA, values, selectionWithId, selectionArgs); 1023c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 102400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 102500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 10267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 10277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS: { 10287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana count = db.update(Tables.CONTACTS, values, selection, selectionArgs); 10297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 10307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 10317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 10327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS_ID: { 10337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String selectionWithId = (Contacts._ID + " = " + ContentUris.parseId(uri) + " ") 10347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana + (selection == null ? "" : " AND " + selection); 10357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana count = db.update(Tables.CONTACTS, values, selectionWithId, selectionArgs); 10367e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana Log.i(TAG, "Selection is: " + selectionWithId); 10377e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 10387e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 10397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 10407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case DATA: { 10417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana count = db.update(Tables.DATA, values, selection, selectionArgs); 10427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 10437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 10447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 1045ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 1046ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey count = db.update(Tables.GROUPS, values, selection, selectionArgs); 1047ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mOpenHelper.updateAllVisible(); 1048ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1049ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1050ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1051ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 1052ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 1053ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String selectionWithId = (Groups._ID + "=" + groupId + " ") 1054ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + (selection == null ? "" : " AND " + selection); 1055ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey count = db.update(Tables.GROUPS, values, selectionWithId, selectionArgs); 1056ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1057ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // If changing visibility, then update aggregates 1058ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (values.containsKey(Groups.GROUP_VISIBLE)) { 1059ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mOpenHelper.updateAllVisible(); 1060ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1061ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1062ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1063ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1064ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1065127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 1066127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov count = updateAggregationException(db, values); 1067b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 1068b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1069b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 1070619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey case RESTRICTION_EXCEPTIONS: { 1071619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Enforce required fields 1072619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean hasFields = values.containsKey(RestrictionExceptions.PACKAGE_PROVIDER) 1073619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey && values.containsKey(RestrictionExceptions.PACKAGE_CLIENT) 1074619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey && values.containsKey(RestrictionExceptions.ALLOW_ACCESS); 1075619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (!hasFields) { 1076619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey throw new IllegalArgumentException("PACKAGE_PROVIDER, PACKAGE_CLIENT, and" 1077619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + "ALLOW_ACCESS are all required fields"); 1078619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1079619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1080619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String packageProvider = values 1081619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey .getAsString(RestrictionExceptions.PACKAGE_PROVIDER); 1082619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final boolean allowAccess = (values 1083619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey .getAsInteger(RestrictionExceptions.ALLOW_ACCESS) == 1); 1084619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1085619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final Context context = getContext(); 1086619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final PackageManager pm = context.getPackageManager(); 1087619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1088619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Enforce that caller has authority over the requested package 1089619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: move back to Binder.getCallingUid() when we can stub-out test suite 1090619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int callingUid = OpenHelper 1091619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey .getUidForPackageName(pm, context.getPackageName()); 1092619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String[] ownedPackages = pm.getPackagesForUid(callingUid); 1093619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (!isContained(ownedPackages, packageProvider)) { 1094619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey throw new RuntimeException( 1095619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey "Requested PACKAGE_PROVIDER doesn't belong to calling UID."); 1096619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1097619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1098619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Add or remove exception using exception helper 1099619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (allowAccess) { 1100619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey mOpenHelper.addRestrictionException(context, values); 1101619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } else { 1102619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey mOpenHelper.removeRestrictionException(context, values); 1103619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1104619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1105619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 1106619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1107619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 11087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana default: 11097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new UnsupportedOperationException("Unknown uri: " + uri); 111000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 111100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 111200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar if (count > 0) { 111300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar getContext().getContentResolver().notifyChange(uri, null); 111400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 111500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 11164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 11174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1118d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov private int updateAggregateData(SQLiteDatabase db, long aggregateId, ContentValues values) { 1119d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1120d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // First update all constituent contacts 1121d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov ContentValues optionValues = new ContentValues(3); 1122d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov if (values.containsKey(Aggregates.CUSTOM_RINGTONE)) { 1123d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov optionValues.put(ContactOptionsColumns.CUSTOM_RINGTONE, 1124d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov values.getAsString(Aggregates.CUSTOM_RINGTONE)); 1125d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1126d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov if (values.containsKey(Aggregates.SEND_TO_VOICEMAIL)) { 1127d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov optionValues.put(ContactOptionsColumns.SEND_TO_VOICEMAIL, 1128d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov values.getAsBoolean(Aggregates.SEND_TO_VOICEMAIL)); 1129d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1130d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1131d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 1132d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov if (optionValues.size() == 0) { 1133d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 1134d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1135d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1136ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Cursor c = db.query(Tables.CONTACTS, Projections.PROJ_CONTACTS, Contacts.AGGREGATE_ID + "=" 1137d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov + aggregateId, null, null, null, null); 1138d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov try { 1139d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov while (c.moveToNext()) { 1140ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long contactId = c.getLong(Projections.COL_CONTACT_ID); 1141d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1142d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov optionValues.put(ContactOptionsColumns._ID, contactId); 1143d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov db.replace(Tables.CONTACT_OPTIONS, null, optionValues); 1144d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1145d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } finally { 1146d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov c.close(); 1147d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1148d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1149d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Now update the aggregate itself. Ignore all supplied fields except rington and 1150d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // send_to_voicemail 1151d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov optionValues.clear(); 1152d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov if (values.containsKey(Aggregates.CUSTOM_RINGTONE)) { 1153d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov optionValues.put(Aggregates.CUSTOM_RINGTONE, 1154d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov values.getAsString(Aggregates.CUSTOM_RINGTONE)); 1155d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1156d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov if (values.containsKey(Aggregates.SEND_TO_VOICEMAIL)) { 1157d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov optionValues.put(Aggregates.SEND_TO_VOICEMAIL, 1158d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov values.getAsBoolean(Aggregates.SEND_TO_VOICEMAIL)); 1159d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1160d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1161d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return db.update(Tables.AGGREGATES, optionValues, Aggregates._ID + "=" + aggregateId, null); 1162d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1163d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1164127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private static class ContactPair { 1165127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov final long contactId1; 1166127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov final long contactId2; 1167127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1168127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov /** 1169127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov * Constructor that ensures that this.contactId1 < this.contactId2 1170127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov */ 1171127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov public ContactPair(long contactId1, long contactId2) { 1172127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov if (contactId1 < contactId2) { 1173127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId1 = contactId1; 1174127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId2 = contactId2; 1175127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } else { 1176127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId2 = contactId1; 1177127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId1 = contactId2; 1178127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1179127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1180127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 118180c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 1182127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 1183127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 1184127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov long aggregateId = values.getAsInteger(AggregationExceptions.AGGREGATE_ID); 1185127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov long contactId = values.getAsInteger(AggregationExceptions.CONTACT_ID); 118680c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 1187127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // First, we build a list of contactID-contactID pairs for the given aggregate and contact. 1188127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov ArrayList<ContactPair> pairs = new ArrayList<ContactPair>(); 1189ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Cursor c = db.query(Tables.CONTACTS, Projections.PROJ_CONTACTS, 1190127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov Contacts.AGGREGATE_ID + "=" + aggregateId, 1191127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov null, null, null, null); 1192127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov try { 1193127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov while (c.moveToNext()) { 1194ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long aggregatedContactId = c.getLong(Projections.COL_CONTACT_ID); 1195e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov if (aggregatedContactId != contactId) { 1196e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov pairs.add(new ContactPair(aggregatedContactId, contactId)); 1197e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov } 1198b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1199b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } finally { 1200b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov c.close(); 1201b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1202127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1203127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // Now we iterate through all contact pairs to see if we need to insert/delete/update 1204127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // the corresponding exception 1205127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 1206127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 1207127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov for (ContactPair pair : pairs) { 1208127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov final String whereClause = 1209127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov AggregationExceptionColumns.CONTACT_ID1 + "=" + pair.contactId1 + " AND " 1210127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov + AggregationExceptionColumns.CONTACT_ID2 + "=" + pair.contactId2; 1211127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 1212127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, whereClause, null); 1213127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } else { 1214127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues.put(AggregationExceptionColumns.CONTACT_ID1, pair.contactId1); 1215127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues.put(AggregationExceptionColumns.CONTACT_ID2, pair.contactId2); 1216127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 1217127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues); 1218127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1219127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1220127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1221127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov mContactAggregator.markContactForAggregation(contactId); 1222127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov mContactAggregator.aggregateContact(contactId); 12237a39bf269294a8130ddd463460b9b36cf4ff74a8Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC 12247a39bf269294a8130ddd463460b9b36cf4ff74a8Dmitri Plotnikov || exceptionType == AggregationExceptions.TYPE_KEEP_OUT) { 12257a39bf269294a8130ddd463460b9b36cf4ff74a8Dmitri Plotnikov mContactAggregator.updateAggregateData(aggregateId); 12267a39bf269294a8130ddd463460b9b36cf4ff74a8Dmitri Plotnikov } 1227127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1228127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 1229127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 1230127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 1231b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1232b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 1233619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1234619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Test if a {@link String} value appears in the given list. 1235619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1236619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private boolean isContained(String[] array, String value) { 1237bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar if (array != null) { 1238bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar for (String test : array) { 1239bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar if (value.equals(test)) { 1240bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar return true; 1241bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar } 1242619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1243619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1244619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return false; 1245619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1246619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1247619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1248619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Test if a {@link String} value appears in the given list, and add to the 1249619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * array if the value doesn't already appear. 1250619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1251619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private String[] assertContained(String[] array, String value) { 1252bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar if (array == null) { 1253bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar array = new String[] {value}; 1254bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar } else if (!isContained(array, value)) { 1255619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey String[] newArray = new String[array.length + 1]; 1256619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey System.arraycopy(array, 0, newArray, 0, array.length); 1257619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey newArray[array.length] = value; 1258619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey array = newArray; 1259619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1260619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return array; 1261619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1262619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 12634f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 12644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 12654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 12664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 126735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1268d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 12691f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 12701f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String limit = null; 1271bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar String aggregateIdColName = Tables.AGGREGATES + "." + Aggregates._ID; 12724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1273619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: Consider writing a test case for RestrictionExceptions when you 1274619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // write a new query() block to make sure it protects restricted data. 1275a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 12764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 127735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 127835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana return mOpenHelper.getSyncState().query(db, projection, selection, selectionArgs, 127935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana sortOrder); 128035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 12816bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES: { 1282b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey qb.setTables(Tables.AGGREGATES); 1283619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1284619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesProjectionMap); 1285619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.setProjectionMap(sAggregatesProjectionMap); 1286619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 1287619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1288619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1289619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey case AGGREGATES_ID: { 1290619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long aggId = ContentUris.parseId(uri); 1291619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.setTables(Tables.AGGREGATES); 1292ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(AggregatesColumns.CONCRETE_ID + "=" + aggId + " AND "); 1293619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1294619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesProjectionMap); 12956bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov qb.setProjectionMap(sAggregatesProjectionMap); 12966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 12976bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 12986bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 12991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case AGGREGATES_SUMMARY: { 1300619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: join into social status tables 13011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1302619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1303619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesSummaryProjectionMap); 1304619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection = assertContained(projection, Aggregates.PRIMARY_PHONE_ID); 13051f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1306bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy = aggregateIdColName; 13071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 13081f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 13091f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 13101f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case AGGREGATES_SUMMARY_ID: { 1311619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: join into social status tables 13121f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey long aggId = ContentUris.parseId(uri); 13131f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1314ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(AggregatesColumns.CONCRETE_ID + "=" + aggId + " AND "); 1315619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1316619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesSummaryProjectionMap); 1317619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection = assertContained(projection, Aggregates.PRIMARY_PHONE_ID); 13181f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1319bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy = aggregateIdColName; 13201f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 13211f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 13221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1323ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case AGGREGATES_SUMMARY_FILTER: { 1324619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: filter query based on callingUid 1325ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1326ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1327ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 1328ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(buildAggregateLookupWhereClause(uri.getLastPathSegment())); 1329ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1330bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy = aggregateIdColName; 1331ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 1332ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1333ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 1334d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar case AGGREGATES_SUMMARY_STREQUENT_FILTER: 1335d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar case AGGREGATES_SUMMARY_STREQUENT: { 1336d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Build the first query for starred 1337d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1338d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1339d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar if (match == AGGREGATES_SUMMARY_STREQUENT_FILTER 1340d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar && uri.getPathSegments().size() > 3) { 1341d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.appendWhere(buildAggregateLookupWhereClause(uri.getLastPathSegment())); 1342d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 1343d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar final String starredQuery = qb.buildQuery(projection, Aggregates.STARRED + "=1", 1344bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar null, aggregateIdColName, null, null, 1345d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar null /* limit */); 1346d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 1347d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Build the second query for frequent 1348d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 1349d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1350d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1351d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar if (match == AGGREGATES_SUMMARY_STREQUENT_FILTER 1352d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar && uri.getPathSegments().size() > 3) { 1353d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.appendWhere(buildAggregateLookupWhereClause(uri.getLastPathSegment())); 1354d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 1355d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar final String frequentQuery = qb.buildQuery(projection, 1356d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar Aggregates.TIMES_CONTACTED + " > 0 AND (" + Aggregates.STARRED 1357d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar + " = 0 OR " + Aggregates.STARRED + " IS NULL)", 1358bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar null, aggregateIdColName, null, null, null); 1359d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 1360d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 1361d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, 1362d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar STREQUENT_ORDER_BY, STREQUENT_LIMIT); 1363d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar Cursor c = db.rawQueryWithFactory(null, query, null, 1364d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1365d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 1366d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar if ((c != null) && !isTemporary()) { 1367d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar c.setNotificationUri(getContext().getContentResolver(), 1368d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 1369d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 1370d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar return c; 1371d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 1372d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 13736bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES_DATA: { 1374619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long aggId = Long.parseLong(uri.getPathSegments().get(1)); 1375ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES); 1376de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar qb.setProjectionMap(sDataContactsAggregateProjectionMap); 1377619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(Contacts.AGGREGATE_ID + "=" + aggId + " AND "); 1378619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 13796bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 13806bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 138100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 1382ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES_FILTER: { 1383ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES); 1384ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sDataContactsAggregateProjectionMap); 1385ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 1386ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 1387ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(" AND " + buildAggregateLookupWhereClause( 1388ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar uri.getLastPathSegment())); 1389ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1390ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 1391ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1392ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1393ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES: { 1394ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES); 1395ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sDataContactsAggregateProjectionMap); 1396ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(Data.MIMETYPE + " = \"" + Phone.CONTENT_ITEM_TYPE + "\""); 1397ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 1398ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1399ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 1400ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 1401ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES); 1402ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sDataContactsAggregateProjectionMap); 1403ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(Data.MIMETYPE + " = \"" + Postal.CONTENT_ITEM_TYPE + "\""); 1404ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 1405ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1406ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 14074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS: { 1408035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana qb.setTables(Tables.CONTACTS_JOIN_PACKAGES); 14094f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton qb.setProjectionMap(sContactsProjectionMap); 1410619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyContactsRestrictionExceptions(qb); 14114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 14124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 14134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 14144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS_ID: { 1415619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long contactId = ContentUris.parseId(uri); 1416035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana qb.setTables(Tables.CONTACTS_JOIN_PACKAGES); 14174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton qb.setProjectionMap(sContactsProjectionMap); 1418ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(ContactsColumns.CONCRETE_ID + "=" + contactId + " AND "); 1419619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyContactsRestrictionExceptions(qb); 14204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 14214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 14224f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1423a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case CONTACTS_DATA: { 1424619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long contactId = Long.parseLong(uri.getPathSegments().get(1)); 1425ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES); 14267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana qb.setProjectionMap(sDataContactsProjectionMap); 1427619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(Data.CONTACT_ID + "=" + contactId + " AND "); 1428619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 1429a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 1430a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1431a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 143228ab0f857caa92402878244d9c5ea2a59e070935Jeff Sharkey case CONTACTS_FILTER_EMAIL: { 1433619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: filter query based on callingUid 1434ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES); 1435e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey qb.setProjectionMap(sDataContactsProjectionMap); 14365d0f923eb4c5351ebf323cc6f19c82acff98693eJeff Sharkey qb.appendWhere(Data.MIMETYPE + "='" + CommonDataKinds.Email.CONTENT_ITEM_TYPE + "'"); 1437e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey qb.appendWhere(" AND " + CommonDataKinds.Email.DATA + "="); 1438e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey qb.appendWhereEscapeString(uri.getPathSegments().get(2)); 1439e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 1440e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 1441e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 1442e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey case DATA: { 1443035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountName = uri.getQueryParameter(Contacts.ACCOUNT_NAME); 1444035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountType = uri.getQueryParameter(Contacts.ACCOUNT_TYPE); 1445343c56b5679c58bf1835a0e219fff57beae6ecefFred Quintana if (!TextUtils.isEmpty(accountName)) { 1446035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana qb.appendWhere(Contacts.ACCOUNT_NAME + "=" 1447035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountName) + " AND " 1448035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + Contacts.ACCOUNT_TYPE + "=" 1449035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountType) + " AND "); 1450343c56b5679c58bf1835a0e219fff57beae6ecefFred Quintana } 1451ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES); 1452e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey qb.setProjectionMap(sDataProjectionMap); 1453619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 1454e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 1455e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 1456e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 14574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case DATA_ID: { 1458ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES); 14594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton qb.setProjectionMap(sDataProjectionMap); 1460ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(DataColumns.CONCRETE_ID + "=" + ContentUris.parseId(uri) + " AND "); 1461619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 14624f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 14634f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 14644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1465a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 1466619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: filter query based on callingUid 1467a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton if (TextUtils.isEmpty(sortOrder)) { 1468a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // Default the sort order to something reasonable so we get consistent 1469a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // results when callers don't request an ordering 1470e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey sortOrder = Data.CONTACT_ID; 1471a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1472a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1473a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final String number = uri.getLastPathSegment(); 1474bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov OpenHelper.buildPhoneLookupQuery(qb, number); 1475a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton qb.setProjectionMap(sDataContactsProjectionMap); 1476a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 1477a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1478a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1479ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 1480ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.GROUPS_JOIN_PACKAGES); 1481ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 1482ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1483ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1484ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1485ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 1486ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 1487ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.GROUPS_JOIN_PACKAGES); 1488ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 1489ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(GroupsColumns.CONCRETE_ID + "=" + groupId); 1490ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1491ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1492ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1493ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 1494ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.GROUPS_JOIN_PACKAGES_DATA_CONTACTS_AGGREGATES); 1495ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsSummaryProjectionMap); 1496ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey groupBy = GroupsColumns.CONCRETE_ID; 1497ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1498ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1499ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1500b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 1501127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS_JOIN_CONTACTS); 1502b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 1503b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 1504b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1505b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 150631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 150731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov long aggregateId = Long.parseLong(uri.getPathSegments().get(1)); 150831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final String maxSuggestionsParam = 150931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov uri.getQueryParameter(AggregationSuggestions.MAX_SUGGESTIONS); 151031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 151131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 151231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (maxSuggestionsParam != null) { 151331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = Integer.parseInt(maxSuggestionsParam); 151431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 151531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 151631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 151731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 151831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov return mContactAggregator.queryAggregationSuggestions(aggregateId, projection, 151931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov sAggregatesProjectionMap, maxSuggestions); 152031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 152131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1522619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey case RESTRICTION_EXCEPTIONS: { 1523619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.setTables(Tables.RESTRICTION_EXCEPTIONS); 1524619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.setProjectionMap(sRestrictionExceptionsProjectionMap); 1525619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 1526619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1527619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 15284f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 15294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton throw new UnsupportedOperationException("Unknown uri: " + uri); 15304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 15314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 15324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Perform the query and set the notification uri 15331f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final Cursor c = qb.query(db, projection, selection, selectionArgs, 1534bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy, null, sortOrder, limit); 15354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 15364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 15374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 15384f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 15394f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 15404f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 15417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 1542619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Restrict selection of {@link Aggregates} to only public ones, or those 1543619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * the caller has been granted a {@link RestrictionExceptions} to. 1544619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1545619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private void applyAggregateRestrictionExceptions(SQLiteQueryBuilder qb) { 1546619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int clientUid = OpenHelper.getUidForPackageName(getContext().getPackageManager(), 1547619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey getContext().getPackageName()); 1548619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1549619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere("(" + AggregatesColumns.SINGLE_RESTRICTED_PACKAGE_ID + " IS NULL"); 1550619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String exceptionClause = mOpenHelper.getRestrictionExceptionClause(clientUid, 1551619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.SINGLE_RESTRICTED_PACKAGE_ID); 1552619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (exceptionClause != null) { 1553619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(" OR (" + exceptionClause + ")"); 1554619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1555619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(")"); 1556619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1557619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1558619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1559619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Find any exceptions that have been granted to the calling process, and 1560619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * add projections to correctly select {@link Aggregates#PRIMARY_PHONE_ID} 1561619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * and {@link Aggregates#PRIMARY_EMAIL_ID}. 1562619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1563619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private void applyAggregatePrimaryRestrictionExceptions(HashMap<String, String> projection) { 1564619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: move back to Binder.getCallingUid() when we can stub-out test suite 1565619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int clientUid = OpenHelper.getUidForPackageName(getContext().getPackageManager(), 1566619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey getContext().getPackageName()); 1567619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1568619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String projectionPhone = "(CASE WHEN " 1569619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + mOpenHelper.getRestrictionExceptionClause(clientUid, 1570619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_PHONE_PACKAGE_ID) + " THEN " 1571619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID + " ELSE " 1572619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID + " END) AS " 1573619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + Aggregates.PRIMARY_PHONE_ID; 1574619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.remove(Aggregates.PRIMARY_PHONE_ID); 1575619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.put(Aggregates.PRIMARY_PHONE_ID, projectionPhone); 1576619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1577619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String projectionEmail = "(CASE WHEN " 1578619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + mOpenHelper.getRestrictionExceptionClause(clientUid, 1579619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_PACKAGE_ID) + " THEN " 1580619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID + " ELSE " 1581619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID + " END) AS " 1582619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + Aggregates.PRIMARY_EMAIL_ID; 1583619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.remove(Aggregates.PRIMARY_EMAIL_ID); 1584619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.put(Aggregates.PRIMARY_EMAIL_ID, projectionEmail); 1585619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1586619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1587619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1588619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Find any exceptions that have been granted to the 1589619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link Binder#getCallingUid()}, and add a limiting clause to the given 1590619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link SQLiteQueryBuilder} to hide restricted data. 1591619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1592619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private void applyContactsRestrictionExceptions(SQLiteQueryBuilder qb) { 1593619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: move back to Binder.getCallingUid() when we can stub-out test suite 1594619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int clientUid = OpenHelper.getUidForPackageName(getContext().getPackageManager(), 1595619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey getContext().getPackageName()); 1596619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1597619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere("(" + Contacts.IS_RESTRICTED + "=0"); 1598619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String exceptionClause = mOpenHelper.getRestrictionExceptionClause(clientUid, 1599619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey ContactsColumns.PACKAGE_ID); 1600619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (exceptionClause != null) { 1601619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(" OR (" + exceptionClause + ")"); 1602619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1603619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(")"); 1604619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1605619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1606619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1607619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Find any exceptions that have been granted to the 1608619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link Binder#getCallingUid()}, and add a limiting clause to the given 1609619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link SQLiteQueryBuilder} to hide restricted data. 1610619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1611619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private void applyDataRestrictionExceptions(SQLiteQueryBuilder qb) { 1612619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyContactsRestrictionExceptions(qb); 1613619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1614619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1615619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 16167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana * An implementation of EntityIterator that joins the contacts and data tables 16177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana * and consumes all the data rows for a contact in order to build the Entity for a contact. 16187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 16197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private static class ContactsEntityIterator implements EntityIterator { 16207e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private final Cursor mEntityCursor; 16217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private volatile boolean mIsClosed; 16227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 16237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private static final String[] DATA_KEYS = new String[]{ 16247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data1", 16257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data2", 16267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data3", 16277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data4", 16287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data5", 16297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data6", 16307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data7", 16317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data8", 16327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data9", 16337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data10"}; 16347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 16357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private static final String[] PROJECTION = new String[]{ 1636035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.ACCOUNT_NAME, 1637035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.ACCOUNT_TYPE, 1638035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.SOURCE_ID, 1639035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.VERSION, 1640035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.DIRTY, 1641035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data._ID, 1642035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.MIMETYPE, 1643035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA1, 1644035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA2, 1645035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA3, 1646035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA4, 1647035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA5, 1648035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA6, 1649035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA7, 1650035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA8, 1651035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA9, 1652035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA10, 1653035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.CONTACT_ID, 1654035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.IS_PRIMARY, 1655035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA_VERSION}; 1656035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana 1657035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_ACCOUNT_NAME = 0; 1658035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_ACCOUNT_TYPE = 1; 1659035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_SOURCE_ID = 2; 1660035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_VERSION = 3; 1661035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_DIRTY = 4; 1662035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_DATA_ID = 5; 1663035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_MIMETYPE = 6; 1664035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_DATA1 = 7; 1665035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_CONTACT_ID = 17; 1666035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_IS_PRIMARY = 18; 1667035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_DATA_VERSION = 19; 16687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 16697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public ContactsEntityIterator(ContactsProvider2 provider, String contactsIdString, Uri uri, 16707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String selection, String[] selectionArgs, String sortOrder) { 16717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mIsClosed = false; 16727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 16737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final String updatedSortOrder = (sortOrder == null) 16747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ? Contacts.Data.CONTACT_ID 16757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana : (Contacts.Data.CONTACT_ID + "," + sortOrder); 16767e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 16777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase(); 16787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 1679ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES); 1680035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana qb.setProjectionMap(sDataContactsProjectionMap); 16817e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (contactsIdString != null) { 16827e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana qb.appendWhere(Data.CONTACT_ID + "=" + contactsIdString); 16837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 1684035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountName = uri.getQueryParameter(Contacts.ACCOUNT_NAME); 1685035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountType = uri.getQueryParameter(Contacts.ACCOUNT_TYPE); 1686035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (!TextUtils.isEmpty(accountName)) { 1687035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana qb.appendWhere(Contacts.ACCOUNT_NAME + "=" 1688035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountName) + " AND " 1689035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + Contacts.ACCOUNT_TYPE + "=" 1690035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountType)); 1691035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 16927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs, 16937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana null, null, updatedSortOrder); 16947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mEntityCursor.moveToFirst(); 16957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 16967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 16977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public void close() { 16987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (mIsClosed) { 16997e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("closing when already closed"); 17007e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mIsClosed = true; 17027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mEntityCursor.close(); 17037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public boolean hasNext() throws RemoteException { 17067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (mIsClosed) { 17077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("calling hasNext() when the iterator is closed"); 17087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return !mEntityCursor.isAfterLast(); 17117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public Entity next() throws RemoteException { 17147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (mIsClosed) { 17157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("calling next() when the iterator is closed"); 17167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (!hasNext()) { 17187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("you may only call next() if hasNext() is true"); 17197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17207e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteCursor c = (SQLiteCursor) mEntityCursor; 17227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final long contactId = c.getLong(COLUMN_CONTACT_ID); 17247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // we expect the cursor is already at the row we need to read from 17267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ContentValues contactValues = new ContentValues(); 1727035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana contactValues.put(Contacts.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME)); 1728035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana contactValues.put(Contacts.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE)); 17297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactValues.put(Contacts._ID, contactId); 17307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactValues.put(Contacts.DIRTY, c.getLong(COLUMN_DIRTY)); 1731f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana contactValues.put(Contacts.VERSION, c.getLong(COLUMN_VERSION)); 17327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactValues.put(Contacts.SOURCE_ID, c.getString(COLUMN_SOURCE_ID)); 17337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana Entity contact = new Entity(contactValues); 17347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // read data rows until the contact id changes 17367e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana do { 17377e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (contactId != c.getLong(COLUMN_CONTACT_ID)) { 17387e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 17397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // add the data to to the contact 17417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ContentValues dataValues = new ContentValues(); 17427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(Contacts.Data._ID, c.getString(COLUMN_DATA_ID)); 1743f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana dataValues.put(Contacts.Data.MIMETYPE, c.getString(COLUMN_MIMETYPE)); 1744f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana dataValues.put(Contacts.Data.IS_PRIMARY, c.getString(COLUMN_IS_PRIMARY)); 1745f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana dataValues.put(Contacts.Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION)); 17467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana for (int i = 0; i < 10; i++) { 17477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final int columnIndex = i + COLUMN_DATA1; 17487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String key = DATA_KEYS[i]; 17497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (c.isNull(columnIndex)) { 17507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // don't put anything 17517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isLong(columnIndex)) { 17527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getLong(columnIndex)); 17537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isFloat(columnIndex)) { 17547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getFloat(columnIndex)); 17557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isString(columnIndex)) { 17567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getString(columnIndex)); 17577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isBlob(columnIndex)) { 17587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getBlob(columnIndex)); 17597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contact.addSubValue(Data.CONTENT_URI, dataValues); 17627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } while (mEntityCursor.moveToNext()); 17637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return contact; 17657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17667e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 1768a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov @Override 17697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs, 17707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String sortOrder) { 17717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final int match = sUriMatcher.match(uri); 17727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana switch (match) { 17737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS: 17747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS_ID: 17757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String contactsIdString = null; 17767e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (match == CONTACTS_ID) { 17777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactsIdString = uri.getPathSegments().get(1); 17787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17807e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return new ContactsEntityIterator(this, contactsIdString, 17817e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana uri, selection, selectionArgs, sortOrder); 17827e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana default: 17837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new UnsupportedOperationException("Unknown uri: " + uri); 17847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 17867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 17884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 1789a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 17904f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 17916bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES: return Aggregates.CONTENT_TYPE; 17926bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES_ID: return Aggregates.CONTENT_ITEM_TYPE; 17934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS: return Contacts.CONTENT_TYPE; 17944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS_ID: return Contacts.CONTENT_ITEM_TYPE; 1795508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 17966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 1797508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 1798b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return mOpenHelper.getDataMimeType(dataId); 179931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: return AggregationExceptions.CONTENT_TYPE; 180031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_EXCEPTION_ID: return AggregationExceptions.CONTENT_ITEM_TYPE; 180131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: return Aggregates.CONTENT_TYPE; 18024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 1803a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton throw new UnsupportedOperationException("Unknown uri: " + uri); 18044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 18057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 1806b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov @Override 18077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 18087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throws OperationApplicationException { 18097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 18117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana db.beginTransaction(); 18127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana try { 18137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ContentProviderResult[] results = super.applyBatch(operations); 18147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana db.setTransactionSuccessful(); 18157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return results; 18167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } finally { 18177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana db.endTransaction(); 18187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 18197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 1820c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1821c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /* 1822c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * Sets the given dataId record in the "data" table to primary, and resets all data records of 1823c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * the same mimetype and under the same contact to not be primary. 1824c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * 1825c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * @param dataId the id of the data record to be set to primary. 1826c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar */ 1827c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private void setIsPrimary(long dataId) { 1828c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.bindLong(1, dataId); 1829c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.bindLong(2, dataId); 1830c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.bindLong(3, dataId); 1831c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.execute(); 1832c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 1833c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1834c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /* 1835c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * Sets the given dataId record in the "data" table to "super primary", and resets all data 1836c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * records of the same mimetype and under the same aggregate to not be "super primary". 1837c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * 1838c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * @param dataId the id of the data record to be set to primary. 1839c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar */ 1840c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private void setIsSuperPrimary(long dataId) { 1841c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.bindLong(1, dataId); 1842c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.bindLong(2, dataId); 1843c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.bindLong(3, dataId); 1844c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.execute(); 1845619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1846619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Find the parent aggregate and package for this new primary 1847619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1848619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1849619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long aggId = -1; 1850619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long packageId = -1; 1851619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean isRestricted = false; 1852619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey String mimeType = null; 1853619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1854619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey Cursor cursor = null; 1855619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey try { 1856ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = db.query(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES, 1857ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Projections.PROJ_DATA_CONTACTS, DataColumns.CONCRETE_ID + "=" + dataId, null, 1858ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey null, null, null); 1859619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (cursor.moveToFirst()) { 1860ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey aggId = cursor.getLong(Projections.COL_AGGREGATE_ID); 1861ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey packageId = cursor.getLong(Projections.COL_PACKAGE_ID); 1862ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey isRestricted = (cursor.getInt(Projections.COL_IS_RESTRICTED) == 1); 1863ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mimeType = cursor.getString(Projections.COL_MIMETYPE); 1864619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1865619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } finally { 1866619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (cursor != null) { 1867619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey cursor.close(); 1868619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1869619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1870619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1871619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Bypass aggregate update if no parent found, or if we don't keep track 1872619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // of super-primary for this mimetype. 1873d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov if (aggId == -1) { 1874d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return; 1875d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1876619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1877619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean isPhone = CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mimeType); 1878619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean isEmail = CommonDataKinds.Email.CONTENT_ITEM_TYPE.equals(mimeType); 1879619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1880619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Record this value as the new primary for the parent aggregate 1881619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final ContentValues values = new ContentValues(); 1882619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (isPhone) { 1883619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID, dataId); 1884619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_PHONE_PACKAGE_ID, packageId); 1885619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } else if (isEmail) { 1886619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID, dataId); 1887619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_PACKAGE_ID, packageId); 1888619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1889619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1890619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // If this data is unrestricted, then also set as fallback 1891619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (!isRestricted && isPhone) { 1892619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID, dataId); 1893619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } else if (!isRestricted && isEmail) { 1894619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID, dataId); 1895619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1896619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1897619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Push update into aggregates table, if needed 1898619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (values.size() > 0) { 1899619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey db.update(Tables.AGGREGATES, values, Aggregates._ID + "=" + aggId, null); 1900619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1901619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1902c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 1903ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 1904ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private String buildAggregateLookupWhereClause(String filterParam) { 1905ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar StringBuilder filter = new StringBuilder(); 1906ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Tables.AGGREGATES); 1907ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append("."); 1908ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Aggregates._ID); 1909ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(" IN (SELECT "); 1910ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Contacts.AGGREGATE_ID); 1911ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(" FROM "); 1912ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Tables.CONTACTS); 1913ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(" WHERE "); 1914ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Contacts._ID); 1915d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar filter.append(" IN (SELECT contact_id FROM name_lookup WHERE normalized_name GLOB '"); 1916ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar // NOTE: Query parameters won't work here since the SQL compiler 1917ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar // needs to parse the actual string to know that it can use the 1918ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar // index to do a prefix scan. 1919d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar filter.append(NameNormalizer.normalize(filterParam) + "*"); 1920d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar filter.append("'))"); 1921ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar return filter.toString(); 1922ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1923ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 19244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 1925