ContactsProvider2.java revision 9261b2141aa90a4fed632fd6da03026d4c216280
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.DataColumns; 2428f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.GroupsColumns; 2528f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.MimetypesColumns; 2628f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.PhoneLookupColumns; 2728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport com.android.providers.contacts.OpenHelper.Tables; 2835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport com.android.internal.content.SyncStateContentProviderHelper; 29b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account; 3035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.pm.PackageManager; 31f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikovimport android.app.SearchManager; 324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.content.ContentProvider; 3335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.UriMatcher; 34b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.content.Context; 3535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentValues; 3635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris; 377e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport android.content.EntityIterator; 3835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.Entity; 3935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentProviderResult; 407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport android.content.OperationApplicationException; 4135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentProviderOperation; 424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor; 43ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils; 44b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.database.sqlite.SQLiteCursor; 454f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase; 464f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder; 47c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millarimport android.database.sqlite.SQLiteStatement; 484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri; 49619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.os.Binder; 50b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException; 51508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns; 52de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract; 536bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikovimport android.provider.Contacts.ContactMethods; 54f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikovimport android.provider.Contacts.People; 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; 105b67163a1088f09c59f324350662eb18772fac6b6Evan Millar private static final int AGGREGATES_SUMMARY_GROUP = 1008; 1064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1076bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int CONTACTS = 2002; 1086bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int CONTACTS_ID = 2003; 1096bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int CONTACTS_DATA = 2004; 11028ab0f857caa92402878244d9c5ea2a59e070935Jeff Sharkey private static final int CONTACTS_FILTER_EMAIL = 2005; 1114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA = 3000; 1136bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA_ID = 3001; 114ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES = 3002; 115ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES_FILTER = 3003; 116ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int POSTALS = 3004; 117a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1186bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int PHONE_LOOKUP = 4000; 1196bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 120b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTIONS = 6000; 121b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTION_ID = 6001; 122b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 1231f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final int PRESENCE = 7000; 1241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final int PRESENCE_ID = 7001; 1251f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 12631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int AGGREGATION_SUGGESTIONS = 8000; 12731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 128619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private static final int RESTRICTION_EXCEPTIONS = 9000; 129619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 130ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS = 10000; 131ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_ID = 10001; 132ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_SUMMARY = 10003; 133ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 13435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private static final int SYNCSTATE = 11000; 13535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 136ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private interface Projections { 1379261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana public static final String[] CONTACTS_ACCOUNT_AND_PACKAGE = 1389261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana new String[]{Contacts.ACCOUNT_NAME, Contacts.ACCOUNT_TYPE, 1399261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana ContactsColumns.PACKAGE_ID}; 1409261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana public static final int CONTACTS_ACCOUNT_AND_PACKAGE_COL_ACCOUNT_NAME = 0; 1419261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana public static final int CONTACTS_ACCOUNT_AND_PACKAGE_COL_ACCOUNT_TYPE = 1; 1429261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana public static final int CONTACTS_ACCOUNT_AND_PACKAGE_COL_PACKAGE_ID = 2; 1439261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 144ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String[] PROJ_CONTACTS = new String[] { 145ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.CONCRETE_ID, 146ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 147ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 148ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String[] PROJ_DATA_CONTACTS = new String[] { 149ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.CONCRETE_ID, 150ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey DataColumns.CONCRETE_ID, 151ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Contacts.AGGREGATE_ID, 152ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.PACKAGE_ID, 153ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Contacts.IS_RESTRICTED, 154ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Data.MIMETYPE, 155ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 156ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 157ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_CONTACT_ID = 0; 158ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_DATA_ID = 1; 159ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_AGGREGATE_ID = 2; 160ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_PACKAGE_ID = 3; 161ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_IS_RESTRICTED = 4; 162ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_MIMETYPE = 5; 163ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 164ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String[] PROJ_DATA_AGGREGATES = new String[] { 165ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.CONCRETE_ID, 166ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey DataColumns.CONCRETE_ID, 167ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.CONCRETE_ID, 168ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey MimetypesColumns.CONCRETE_ID, 169ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Phone.NUMBER, 170ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Email.DATA, 171ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID, 172ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID, 173ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID, 174ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID, 175ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 176ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 177ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_MIMETYPE_ID = 3; 178ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_PHONE_NUMBER = 4; 179ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_EMAIL_DATA = 5; 180ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_OPTIMAL_PHONE_ID = 6; 181ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_FALLBACK_PHONE_ID = 7; 182ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_OPTIMAL_EMAIL_ID = 8; 183ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final int COL_FALLBACK_EMAIL_ID = 9; 18480c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 185ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1861f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 18731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /** Default for the maximum number of returned aggregation suggestions. */ 18831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int DEFAULT_MAX_SUGGESTIONS = 5; 18931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** Contains just the contacts columns */ 1916bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final HashMap<String, String> sAggregatesProjectionMap; 19200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar /** Contains the aggregate columns along with primary phone */ 1931f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final HashMap<String, String> sAggregatesSummaryProjectionMap; 194de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar /** Contains the data, contacts, and aggregate columns, for joined tables. */ 195de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar private static final HashMap<String, String> sDataContactsAggregateProjectionMap; 1969261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data, contacts, group sourceid and aggregate columns, for joined tables. */ 1979261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana private static final HashMap<String, String> sDataContactsGroupsAggregateProjectionMap; 198a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** Contains just the contacts columns */ 1994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton private static final HashMap<String, String> sContactsProjectionMap; 200a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** Contains just the data columns */ 2019261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana private static final HashMap<String, String> sDataGroupsProjectionMap; 2029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data and contacts columns, for joined tables */ 2039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana private static final HashMap<String, String> sDataContactsGroupsProjectionMap; 204a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** Contains the data and contacts columns, for joined tables */ 205a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton private static final HashMap<String, String> sDataContactsProjectionMap; 206ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains the just the {@link Groups} columns */ 207ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final HashMap<String, String> sGroupsProjectionMap; 208ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains {@link Groups} columns along with summary details */ 209ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final HashMap<String, String> sGroupsSummaryProjectionMap; 210b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov /** Contains the just the agg_exceptions columns */ 211b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final HashMap<String, String> sAggregationExceptionsProjectionMap; 212619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** Contains the just the {@link RestrictionExceptions} columns */ 213619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private static final HashMap<String, String> sRestrictionExceptionsProjectionMap; 2147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 215c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns the contact id associated with a data record. */ 216c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedContactIdSelect; 217c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns the mimetype id associated with a data record. */ 218c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedMimetypeSelect; 219c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns the aggregate id associated with a contact record. */ 220c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedAggregateIdSelect; 221c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql select statement that returns a list of contact ids associated with an aggregate record. */ 222c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sNestedContactIdListSelect; 223c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql where statement used to match all the data records that need to be updated when a new 224c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * "primary" is selected.*/ 225c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sSetPrimaryWhere; 226c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Sql where statement used to match all the data records that need to be updated when a new 227c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * "super primary" is selected.*/ 228c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private static final String sSetSuperPrimaryWhere; 229b67163a1088f09c59f324350662eb18772fac6b6Evan Millar /** Sql where statement for filtering on groups. */ 230b67163a1088f09c59f324350662eb18772fac6b6Evan Millar private static final String sAggregatesInGroupSelect; 231c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Precompiled sql statement for setting a data record to the primary. */ 232c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private SQLiteStatement mSetPrimaryStatement; 233c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /** Precomipled sql statement for setting a data record to the super primary. */ 234c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private SQLiteStatement mSetSuperPrimaryStatement; 235f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov /** Precomipled sql statement for incrementing times contacted for an aggregate */ 236f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private SQLiteStatement mLastTimeContactedUpdate; 237a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 2381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final String GTALK_PROTOCOL_STRING = ContactMethods 2391f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey .encodePredefinedImProtocol(ContactMethods.PROTOCOL_GOOGLE_TALK); 2401f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 2424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 243a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 2446bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates", AGGREGATES); 2456bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates/#", AGGREGATES_ID); 2466bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates/#/data", AGGREGATES_DATA); 2471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary", AGGREGATES_SUMMARY); 2481f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/#", AGGREGATES_SUMMARY_ID); 249ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/filter/*", 250ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar AGGREGATES_SUMMARY_FILTER); 251d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/strequent/", 252d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar AGGREGATES_SUMMARY_STREQUENT); 253d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/strequent/filter/*", 254d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar AGGREGATES_SUMMARY_STREQUENT_FILTER); 255b67163a1088f09c59f324350662eb18772fac6b6Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "aggregates_summary/group/*", 256b67163a1088f09c59f324350662eb18772fac6b6Evan Millar AGGREGATES_SUMMARY_GROUP); 25731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregates/#/suggestions", 25831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 2594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 2604f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 261a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_DATA); 262b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter_email/*", 263b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov CONTACTS_FILTER_EMAIL); 264b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 2654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 2664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 267ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 268ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 269ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 2701f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 271ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 272ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 273ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 274ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 27535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 27635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 277a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 278b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 279b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 280b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 281b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 2824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 283bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "presence", PRESENCE); 284bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "presence/#", PRESENCE_ID); 2851f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 286619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "restriction_exceptions", RESTRICTION_EXCEPTIONS); 287619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 288fec4e13316f2731d84394e5fa2f93af3febdc20cEvan Millar HashMap<String, String> columns; 2894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov // Aggregates projection map 2916bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns = new HashMap<String, String>(); 29200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar columns.put(Aggregates._ID, "aggregates._id AS _id"); 2936bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns.put(Aggregates.DISPLAY_NAME, Aggregates.DISPLAY_NAME); 2946bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns.put(Aggregates.LAST_TIME_CONTACTED, Aggregates.LAST_TIME_CONTACTED); 295d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar columns.put(Aggregates.TIMES_CONTACTED, Aggregates.TIMES_CONTACTED); 2966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns.put(Aggregates.STARRED, Aggregates.STARRED); 297ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Aggregates.IN_VISIBLE_GROUP, Aggregates.IN_VISIBLE_GROUP); 298ae6ca1f34cf5458d79ec803411d4308879a91e92Evan Millar columns.put(Aggregates.PHOTO_ID, Aggregates.PHOTO_ID); 299de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar columns.put(Aggregates.PRIMARY_PHONE_ID, Aggregates.PRIMARY_PHONE_ID); 300c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar columns.put(Aggregates.PRIMARY_EMAIL_ID, Aggregates.PRIMARY_EMAIL_ID); 301d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov columns.put(Aggregates.CUSTOM_RINGTONE, Aggregates.CUSTOM_RINGTONE); 302d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov columns.put(Aggregates.SEND_TO_VOICEMAIL, Aggregates.SEND_TO_VOICEMAIL); 303619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID, 304619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID); 305619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID, 306619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID); 3076bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov sAggregatesProjectionMap = columns; 3086bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 3091f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // Aggregates primaries projection map. The overall presence status is 3101f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // the most-present value, as indicated by the largest value. 3111f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey columns = new HashMap<String, String>(); 3121f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey columns.putAll(sAggregatesProjectionMap); 31300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar columns.put(CommonDataKinds.Phone.TYPE, CommonDataKinds.Phone.TYPE); 31400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar columns.put(CommonDataKinds.Phone.LABEL, CommonDataKinds.Phone.LABEL); 31500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar columns.put(CommonDataKinds.Phone.NUMBER, CommonDataKinds.Phone.NUMBER); 316bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar columns.put(Presence.PRESENCE_STATUS, "MAX(" + Presence.PRESENCE_STATUS + ")"); 3171f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey sAggregatesSummaryProjectionMap = columns; 31800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 3194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts projection map 3204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns = new HashMap<String, String>(); 3214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns.put(Contacts._ID, "contacts._id AS _id"); 322619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(Contacts.PACKAGE, Contacts.PACKAGE); 3236bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov columns.put(Contacts.AGGREGATE_ID, Contacts.AGGREGATE_ID); 3249261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Contacts.ACCOUNT_NAME, 3259261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana OpenHelper.ContactsColumns.CONCRETE_ACCOUNT_NAME + " as " + Contacts.ACCOUNT_NAME); 3269261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Contacts.ACCOUNT_TYPE, 3279261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana OpenHelper.ContactsColumns.CONCRETE_ACCOUNT_TYPE + " as " + Contacts.ACCOUNT_TYPE); 3289261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Contacts.SOURCE_ID, 3299261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana OpenHelper.ContactsColumns.CONCRETE_SOURCE_ID + " as " + Contacts.SOURCE_ID); 3309261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Contacts.VERSION, 3319261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana OpenHelper.ContactsColumns.CONCRETE_VERSION + " as " + Contacts.VERSION); 3329261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Contacts.DIRTY, 3339261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana OpenHelper.ContactsColumns.CONCRETE_DIRTY + " as " + Contacts.DIRTY); 3344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton sContactsProjectionMap = columns; 3354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 3364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Data projection map 3374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns = new HashMap<String, String>(); 3384f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns.put(Data._ID, "data._id AS _id"); 3394f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton columns.put(Data.CONTACT_ID, Data.CONTACT_ID); 340508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey columns.put(Data.MIMETYPE, Data.MIMETYPE); 341c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar columns.put(Data.IS_PRIMARY, Data.IS_PRIMARY); 342c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar columns.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY); 343f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana columns.put(Data.DATA_VERSION, Data.DATA_VERSION); 3447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA1, "data.data1 as data1"); 3457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA2, "data.data2 as data2"); 3467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA3, "data.data3 as data3"); 3477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA4, "data.data4 as data4"); 3487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA5, "data.data5 as data5"); 3497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA6, "data.data6 as data6"); 3507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA7, "data.data7 as data7"); 3517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA8, "data.data8 as data8"); 3527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA9, "data.data9 as data9"); 3537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.put(Data.DATA10, "data.data10 as data10"); 3549261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(GroupMembership.GROUP_SOURCE_ID, "groups.sourceid as " + GroupMembership.GROUP_SOURCE_ID); 355d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Mappings used for backwards compatibility. 356d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar columns.put("number", Phone.NUMBER); 3579261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana sDataGroupsProjectionMap = columns; 358a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 3599261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana // Data, groups and contacts projection map for joins. _id comes from the data table 360a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton columns = new HashMap<String, String>(); 361a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton columns.putAll(sContactsProjectionMap); 3629261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.putAll(sDataGroupsProjectionMap); // _id will be replaced with the one from data 363ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Data.CONTACT_ID, DataColumns.CONCRETE_CONTACT_ID); 3649261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana sDataContactsGroupsProjectionMap = columns; 3659261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 3669261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana // Data and contacts projection map for joins. _id comes from the data table 3679261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns = new HashMap<String, String>(); 3689261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.putAll(sDataContactsGroupsProjectionMap); 3699261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.remove(GroupMembership.GROUP_SOURCE_ID); 370a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton sDataContactsProjectionMap = columns; 3717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 372de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar // Data and contacts projection map for joins. _id comes from the data table 373de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar columns = new HashMap<String, String>(); 374de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar columns.putAll(sAggregatesProjectionMap); 3757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana columns.putAll(sContactsProjectionMap); // 3769261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.putAll(sDataGroupsProjectionMap); // _id will be replaced with the one from data 377ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Data.CONTACT_ID, DataColumns.CONCRETE_CONTACT_ID); 3789261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana sDataContactsGroupsAggregateProjectionMap = columns; 3799261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 3809261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana // Data and contacts projection map for joins. _id comes from the data table 3819261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns = new HashMap<String, String>(); 3829261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.putAll(sDataContactsGroupsAggregateProjectionMap); 3839261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.remove(GroupMembership.GROUP_SOURCE_ID); 384de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar sDataContactsAggregateProjectionMap = columns; 385c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 386ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Groups projection map 387ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns = new HashMap<String, String>(); 388ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups._ID, "groups._id AS _id"); 389035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana columns.put(Groups.ACCOUNT_NAME, Groups.ACCOUNT_NAME); 390035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana columns.put(Groups.ACCOUNT_TYPE, Groups.ACCOUNT_TYPE); 3919261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Groups.SOURCE_ID, Groups.SOURCE_ID); 3929261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Groups.DIRTY, Groups.DIRTY); 3939261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana columns.put(Groups.VERSION, Groups.VERSION); 394ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.PACKAGE, Groups.PACKAGE); 395ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.PACKAGE_ID, GroupsColumns.CONCRETE_PACKAGE_ID); 396ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.TITLE, Groups.TITLE); 397ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.TITLE_RESOURCE, Groups.TITLE_RESOURCE); 398ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.GROUP_VISIBLE, Groups.GROUP_VISIBLE); 399ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey sGroupsProjectionMap = columns; 400ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 401ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Contacts and groups projection map 402ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns = new HashMap<String, String>(); 403ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.putAll(sGroupsProjectionMap); 404ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 405ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.SUMMARY_COUNT, "(SELECT COUNT(DISTINCT " + AggregatesColumns.CONCRETE_ID 406ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + ") FROM " + Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES + " WHERE " 407ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP 408ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + ") AS " + Groups.SUMMARY_COUNT); 409ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 410ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey columns.put(Groups.SUMMARY_WITH_PHONES, "(SELECT COUNT(DISTINCT " 411ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + AggregatesColumns.CONCRETE_ID + ") FROM " 412ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES + " WHERE " 413ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP + " AND " + Clauses.BELONGS_TO_GROUP 414ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + " AND " + Clauses.HAS_PRIMARY_PHONE + ") AS " + Groups.SUMMARY_WITH_PHONES); 415ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 416ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey sGroupsSummaryProjectionMap = columns; 417ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 418b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov // Aggregate exception projection map 419b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov columns = new HashMap<String, String>(); 420b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov columns.put(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id AS _id"); 421b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov columns.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE); 422127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov columns.put(AggregationExceptions.AGGREGATE_ID, 423127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov "contacts1." + Contacts.AGGREGATE_ID + " AS " + AggregationExceptions.AGGREGATE_ID); 424127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov columns.put(AggregationExceptions.CONTACT_ID, AggregationExceptionColumns.CONTACT_ID2); 425b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov sAggregationExceptionsProjectionMap = columns; 426b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 427619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Restriction exception projection map 428619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns = new HashMap<String, String>(); 429619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(RestrictionExceptions.PACKAGE_PROVIDER, RestrictionExceptions.PACKAGE_PROVIDER); 430619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(RestrictionExceptions.PACKAGE_CLIENT, RestrictionExceptions.PACKAGE_CLIENT); 431619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey columns.put(RestrictionExceptions.ALLOW_ACCESS, "1"); // Access granted if row returned 432619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey sRestrictionExceptionsProjectionMap = columns; 433619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 434c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedContactIdSelect = "SELECT " + Data.CONTACT_ID + " FROM " + Tables.DATA + " WHERE " 435c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + Data._ID + "=?"; 436c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedMimetypeSelect = "SELECT " + DataColumns.MIMETYPE_ID + " FROM " + Tables.DATA 437c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + " WHERE " + Data._ID + "=?"; 438c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedAggregateIdSelect = "SELECT " + Contacts.AGGREGATE_ID + " FROM " + Tables.CONTACTS 439c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + " WHERE " + Contacts._ID + "=(" + sNestedContactIdSelect + ")"; 440c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sNestedContactIdListSelect = "SELECT " + Contacts._ID + " FROM " + Tables.CONTACTS 441c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + " WHERE " + Contacts.AGGREGATE_ID + "=(" + sNestedAggregateIdSelect + ")"; 442c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar sSetPrimaryWhere = Data.CONTACT_ID + "=(" + sNestedContactIdSelect + ") AND " 443c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + DataColumns.MIMETYPE_ID + "=(" + sNestedMimetypeSelect + ")"; 444b67163a1088f09c59f324350662eb18772fac6b6Evan Millar sSetSuperPrimaryWhere = Data.CONTACT_ID + " IN (" + sNestedContactIdListSelect + ") AND " 445c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + DataColumns.MIMETYPE_ID + "=(" + sNestedMimetypeSelect + ")"; 446b67163a1088f09c59f324350662eb18772fac6b6Evan Millar sAggregatesInGroupSelect = AggregatesColumns.CONCRETE_ID + " IN (SELECT " 447b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + Contacts.AGGREGATE_ID + " FROM " + Tables.CONTACTS + " WHERE (" 448b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + ContactsColumns.CONCRETE_ID + " IN (SELECT " + Tables.DATA + "." 449b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + Data.CONTACT_ID + " FROM " + Tables.DATA_JOIN_MIMETYPES + " WHERE (" 450b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE + "' AND " 451b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + GroupMembership.GROUP_ROW_ID + "=(SELECT " + Tables.GROUPS + "." 452b67163a1088f09c59f324350662eb18772fac6b6Evan Millar + Groups._ID + " FROM " + Tables.GROUPS + " WHERE " + Groups.TITLE + "=?)))))"; 4534f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 4544f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 45553056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov private final ContactAggregationScheduler mAggregationScheduler; 4564f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton private OpenHelper mOpenHelper; 45731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 458a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov private ContactAggregator mContactAggregator; 4594097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 460f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private LegacyApiSupport mLegacyApiSupport; 461a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 462a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public ContactsProvider2() { 46353056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov this(new ContactAggregationScheduler()); 464a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 465a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 466a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 467a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Constructor for testing. 468a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 46953056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov /* package */ ContactsProvider2(ContactAggregationScheduler scheduler) { 47053056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov mAggregationScheduler = scheduler; 471a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 4724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 4734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 4744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 475b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey final Context context = getContext(); 47635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 47731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov mOpenHelper = getOpenHelper(context); 4781f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 4794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 48053056d49d8adf5d1fe2d18cb60c3c26f281e7a6cDmitri Plotnikov mContactAggregator = new ContactAggregator(context, mOpenHelper, mAggregationScheduler); 481a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 482c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement = db.compileStatement( 483c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar "UPDATE " + Tables.DATA + " SET " + Data.IS_PRIMARY 484c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + "=(_id=?) WHERE " + sSetPrimaryWhere); 485c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement = db.compileStatement( 486c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar "UPDATE " + Tables.DATA + " SET " + Data.IS_SUPER_PRIMARY 487c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar + "=(_id=?) WHERE " + sSetSuperPrimaryWhere); 488f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mLastTimeContactedUpdate = db.compileStatement("UPDATE " + Tables.CONTACTS + " SET " 489f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov + Contacts.TIMES_CONTACTED + "=" + Contacts.TIMES_CONTACTED + "+1," 490f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov + Contacts.LAST_TIME_CONTACTED + "=? WHERE " + Contacts.AGGREGATE_ID + "=?"); 491a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 49228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar mNameSplitter = new NameSplitter( 49328f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_name_prefixes), 49428f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_last_name_prefixes), 49528f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_name_suffixes), 49628f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar context.getString(com.android.internal.R.string.common_name_conjunctions)); 4974097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 498f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mLegacyApiSupport = new LegacyApiSupport(context, mOpenHelper, this); 4991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return (db != null); 5004f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 5014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 50231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /* Visible for testing */ 50331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov protected OpenHelper getOpenHelper(final Context context) { 50431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov return OpenHelper.getInstance(context); 50531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 50631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 507a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov @Override 508a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov protected void finalize() throws Throwable { 509a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov if (mContactAggregator != null) { 510a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov mContactAggregator.quit(); 511a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 512a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 513a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov super.finalize(); 514a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 515a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 516a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 517a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 518a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 519a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /* package */ void wipeData() { 520a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov mOpenHelper.wipeData(); 521a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 522a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 523a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 524a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Called when a change has been made. 525a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 526a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param uri the uri that the change was made to 527a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 528a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton private void onChange(Uri uri) { 529a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null); 530a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 531a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 5334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean isTemporary() { 5344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return false; 5354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 5364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 5374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 5384f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Uri insert(Uri uri, ContentValues values) { 539a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 540a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 54135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 542a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 54335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 54435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana id = mOpenHelper.getSyncState().insert(mOpenHelper.getWritableDatabase(), values); 54535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 54635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 5476bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES: { 548f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov insertAggregate(values); 5496bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 5506bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 5516bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 552a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case CONTACTS: { 553f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana final Account account = readAccountFromQueryParams(uri); 554f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana id = insertContact(values, account); 555a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 556a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 557a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 558a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case CONTACTS_DATA: { 559a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton values.put(Data.CONTACT_ID, uri.getPathSegments().get(1)); 560035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana id = insertData(values); 561a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 562a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 563a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 564a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case DATA: { 565035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana id = insertData(values); 566a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 567a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 568a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 569ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 570ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final Account account = readAccountFromQueryParams(uri); 571ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey id = insertGroup(values, account); 572ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 573ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 574ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5751f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case PRESENCE: { 5761f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey id = insertPresence(values); 5771f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 5781f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 5791f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 580a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 581f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.insert(uri, values); 582a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 583a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 5857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 5867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 5877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 5887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final Uri result = ContentUris.withAppendedId(uri, id); 589a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton onChange(result); 590a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return result; 591a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 592a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 593a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 594035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * If account is non-null then store it in the values. If the account is already 595035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * specified in the values then it must be consistent with the account, if it is non-null. 596035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * @param values the ContentValues to read from and update 597035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * @param account the explicitly provided Account 598035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana * @return false if the accounts are inconsistent 5997e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 600035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private boolean resolveAccount(ContentValues values, Account account) { 601035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana // If either is specified then both must be specified. 602035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountName = values.getAsString(Contacts.ACCOUNT_NAME); 603035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountType = values.getAsString(Contacts.ACCOUNT_TYPE); 604035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (!TextUtils.isEmpty(accountName) || !TextUtils.isEmpty(accountType)) { 605035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final Account valuesAccount = new Account(accountName, accountType); 606035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (account != null && !valuesAccount.equals(account)) { 607035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana return false; 608035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 609035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana account = valuesAccount; 610035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 611035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (account != null) { 612035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana values.put(Contacts.ACCOUNT_NAME, account.mName); 613035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana values.put(Contacts.ACCOUNT_TYPE, account.mType); 614035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 615035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana return true; 6167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 6177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 6187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 6196bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * Inserts an item in the aggregates table 6206bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 6216bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 6226bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 6236bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 6246bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private long insertAggregate(ContentValues values) { 625a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov throw new UnsupportedOperationException("Aggregates are created automatically"); 6266bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 6276bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 6286bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 629a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the contacts table 630a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 631a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 632f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana * @param account the account this contact should be associated with. may be null. 633a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 634a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 635f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana private long insertContact(ContentValues values, Account account) { 6366bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /* 6376bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * The contact record is inserted in the contacts table, but it needs to 6386bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * be processed by the aggregator before it will be returned by the 6396bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * "aggregates" queries. 6406bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 641a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 6426bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 643a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov ContentValues overriddenValues = new ContentValues(values); 644a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov overriddenValues.putNull(Contacts.AGGREGATE_ID); 645f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana if (!resolveAccount(overriddenValues, account)) { 6467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return -1; 6477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 6487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 649619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Replace package with internal mapping 650619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String packageName = overriddenValues.getAsString(Contacts.PACKAGE); 651619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey overriddenValues.put(ContactsColumns.PACKAGE_ID, mOpenHelper.getPackageId(packageName)); 652619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey overriddenValues.remove(Contacts.PACKAGE); 653619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 654f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov long contactId = db.insert(Tables.CONTACTS, Contacts.AGGREGATE_ID, overriddenValues); 655f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov 656f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov int aggregationMode = Contacts.AGGREGATION_MODE_DEFAULT; 657f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov if (values.containsKey(Contacts.AGGREGATION_MODE)) { 658f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov aggregationMode = values.getAsInteger(Contacts.AGGREGATION_MODE); 659f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 660a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 661f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov triggerAggregation(contactId, aggregationMode); 662a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 663f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return contactId; 664a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 665a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 666a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 667a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 668a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 669a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 670a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 671a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 672035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private long insertData(ContentValues values) { 673f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov int aggregationMode = Contacts.AGGREGATION_MODE_DISABLED; 674a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 675a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 676a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 677a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton db.beginTransaction(); 678a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton try { 679a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov long contactId = values.getAsLong(Data.CONTACT_ID); 680a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 681619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Replace mimetype with internal mapping 682508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final String mimeType = values.getAsString(Data.MIMETYPE); 683b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey values.put(DataColumns.MIMETYPE_ID, mOpenHelper.getMimeTypeId(mimeType)); 684508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey values.remove(Data.MIMETYPE); 685508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 6864097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) { 6874097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov parseStructuredName(values); 6889261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } else if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) { 6899261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana boolean containsGroupSourceId = values.containsKey(GroupMembership.GROUP_SOURCE_ID); 6909261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana boolean containsGroupId = values.containsKey(GroupMembership.GROUP_ROW_ID); 6919261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (containsGroupSourceId && containsGroupId) { 6929261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana throw new IllegalArgumentException( 6939261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana "you are not allowed to set both the GroupMembership.GROUP_SOURCE_ID " 6949261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana + "and GroupMembership.GROUP_ROW_ID"); 6959261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 6969261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 6979261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (!containsGroupSourceId && !containsGroupId) { 6989261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana throw new IllegalArgumentException( 6999261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana "you must set exactly one of GroupMembership.GROUP_SOURCE_ID " 7009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana + "and GroupMembership.GROUP_ROW_ID"); 7019261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 7029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 7039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (containsGroupSourceId) { 7049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana final String sourceId = values.getAsString(GroupMembership.GROUP_SOURCE_ID); 7059261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana final long groupId = getOrMakeGroup(db, contactId, sourceId); 7069261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana values.remove(GroupMembership.GROUP_SOURCE_ID); 7079261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana values.put(GroupMembership.GROUP_ROW_ID, groupId); 7089261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 7094097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov } 7104097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 711508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey // Insert the data row itself 712b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey id = db.insert(Tables.DATA, Data.DATA1, values); 713508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 714a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // If it's a phone number add the normalized version to the lookup table 7154097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) { 716508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final ContentValues phoneValues = new ContentValues(); 717508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final String number = values.getAsString(Phone.NUMBER); 718508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, 719508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey PhoneNumberUtils.getStrippedReversed(number)); 720508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey phoneValues.put(PhoneLookupColumns.DATA_ID, id); 721a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov phoneValues.put(PhoneLookupColumns.CONTACT_ID, contactId); 722b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.insert(Tables.PHONE_LOOKUP, null, phoneValues); 723a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 724a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 725f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov aggregationMode = mContactAggregator.markContactForAggregation(contactId); 726a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 727a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton db.setTransactionSuccessful(); 728a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } finally { 729a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton db.endTransaction(); 730a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 731a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 732f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov triggerAggregation(id, aggregationMode); 733a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 7344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 7354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 736f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private void triggerAggregation(long contactId, int aggregationMode) { 737f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov switch (aggregationMode) { 738f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov case Contacts.AGGREGATION_MODE_DEFAULT: 739f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mContactAggregator.schedule(); 740f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov break; 741f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov 742f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov case Contacts.AGGREGATION_MODE_IMMEDITATE: 743f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mContactAggregator.aggregateContact(contactId); 744f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov break; 745f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov 746f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov case Contacts.AGGREGATION_MODE_DISABLED: 747f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov // Do nothing 748f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov break; 749f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 750f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 751f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov 752a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 7539261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * Returns the group id of the group with sourceId and the same account as contactId. 7549261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * If the group doesn't already exist then it is first created, 7559261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @param db SQLiteDatabase to use for this operation 7569261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @param contactId the contact this group is associated with 7579261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @param sourceId the sourceIf of the group to query or create 7589261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @return the group id of the existing or created group 7599261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @throws IllegalArgumentException if the contact is not associated with an account 7609261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana * @throws IllegalStateException if a group needs to be created but the creation failed 7619261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana */ 7629261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana private long getOrMakeGroup(SQLiteDatabase db, long contactId, String sourceId) { 7639261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana Account account = null; 7649261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana long contactPackage = -1; 7659261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana Cursor c = db.query(Tables.CONTACTS, 7669261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana Projections.CONTACTS_ACCOUNT_AND_PACKAGE, 7679261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana Contacts._ID + "=" + contactId, null, null, null, null); 7689261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana try { 7699261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (c.moveToNext()) { 7709261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana final String accountName = 7719261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana c.getString(Projections.CONTACTS_ACCOUNT_AND_PACKAGE_COL_ACCOUNT_NAME); 7729261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana final String accountType = 7739261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana c.getString(Projections.CONTACTS_ACCOUNT_AND_PACKAGE_COL_ACCOUNT_TYPE); 7749261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { 7759261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana account = new Account(accountName, accountType); 7769261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 7779261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana contactPackage = c.getLong(Projections.CONTACTS_ACCOUNT_AND_PACKAGE_COL_PACKAGE_ID); 7789261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 7799261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } finally { 7809261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana c.close(); 7819261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 7829261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (account == null) { 7839261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana throw new IllegalArgumentException("if the groupmembership only " 7849261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana + "has a sourceid the the contact must be associate with " 7859261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana + "an account"); 7869261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 7879261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 7889261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana // look up the group that contains this sourceId and has the same account name and type 7899261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana // as the contact refered to by contactId 7909261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana c = db.query(Tables.GROUPS, new String[]{Contacts._ID}, 7919261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana Clauses.GROUP_HAS_ACCOUNT_AND_SOURCE_ID, 7929261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana new String[]{sourceId, account.mName, account.mType}, null, null, null); 7939261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana try { 7949261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (c.moveToNext()) { 7959261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana return c.getLong(0); 7969261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } else { 7979261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana ContentValues groupValues = new ContentValues(); 7989261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana groupValues.put(Groups.PACKAGE_ID, contactPackage); 7999261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana groupValues.put(Groups.ACCOUNT_NAME, account.mName); 8009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana groupValues.put(Groups.ACCOUNT_TYPE, account.mType); 8019261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana groupValues.put(Groups.SOURCE_ID, sourceId); 8029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana long groupId = db.insert(Tables.GROUPS, Groups.ACCOUNT_NAME, groupValues); 8039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (groupId < 0) { 8049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana throw new IllegalStateException("unable to create a new group with " 8059261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana + "this sourceid: " + groupValues); 8069261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 8079261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana return groupId; 8089261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 8099261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } finally { 8109261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana c.close(); 8119261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 8129261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 8139261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana 8149261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** 815ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Delete the given {@link Data} row, fixing up any {@link Aggregates} 816ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * primaries that reference it. 817ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 818ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private int deleteData(long dataId) { 819ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 820ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 821ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long mimePhone = mOpenHelper.getMimeTypeId(Phone.CONTENT_ITEM_TYPE); 822ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long mimeEmail = mOpenHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE); 823ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 824ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Check to see if the data about to be deleted was a super-primary on 825ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // the parent aggregate, and set flags to fix-up once deleted. 826ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long aggId = -1; 827ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long mimeId = -1; 828ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String dataRaw = null; 829ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey boolean fixOptimal = false; 830ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey boolean fixFallback = false; 831ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 832ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Cursor cursor = null; 833ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey try { 834ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = db.query(Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES, 835ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Projections.PROJ_DATA_AGGREGATES, DataColumns.CONCRETE_ID + "=" + dataId, null, 836ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey null, null, null); 837ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (cursor.moveToFirst()) { 838ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey aggId = cursor.getLong(Projections.COL_AGGREGATE_ID); 839ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mimeId = cursor.getLong(Projections.COL_MIMETYPE_ID); 840ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 841ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey dataRaw = cursor.getString(Projections.COL_PHONE_NUMBER); 842ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey fixOptimal = (cursor.getLong(Projections.COL_OPTIMAL_PHONE_ID) == dataId); 843ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey fixFallback = (cursor.getLong(Projections.COL_FALLBACK_PHONE_ID) == dataId); 844ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 845ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey dataRaw = cursor.getString(Projections.COL_EMAIL_DATA); 846ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey fixOptimal = (cursor.getLong(Projections.COL_OPTIMAL_EMAIL_ID) == dataId); 847ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey fixFallback = (cursor.getLong(Projections.COL_FALLBACK_EMAIL_ID) == dataId); 848ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 849ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 850ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } finally { 851ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (cursor != null) { 852ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor.close(); 853ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = null; 854ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 855ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 856ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 857ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Delete the requested data item. 858ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey int dataDeleted = db.delete(Tables.DATA, Data._ID + "=" + dataId, null); 859ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 860ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Fix-up any super-primary values that are now invalid. 861ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (fixOptimal || fixFallback) { 862ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final ContentValues values = new ContentValues(); 863ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final StringBuilder scoreClause = new StringBuilder(); 864ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 865ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final String SCORE = "score"; 866ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 867ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Build scoring clause that will first pick data items under the 868ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // same aggregate that have identical values, otherwise fall back to 869ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // normal primary scoring from the member contacts. 870ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append("(CASE WHEN "); 871ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 872ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append(Phone.NUMBER); 873ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 874ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append(Email.DATA); 875ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 876ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append("="); 877ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey DatabaseUtils.appendEscapedSQLString(scoreClause, dataRaw); 878ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.append(" THEN 2 ELSE " + Data.IS_PRIMARY + " END) AS " + SCORE); 879ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 880ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final String[] PROJ_PRIMARY = new String[] { 881ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey DataColumns.CONCRETE_ID, 882ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Contacts.IS_RESTRICTED, 883ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContactsColumns.PACKAGE_ID, 884ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey scoreClause.toString(), 885ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 886ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 887ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final int COL_DATA_ID = 0; 888ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final int COL_IS_RESTRICTED = 1; 889ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final int COL_PACKAGE_ID = 2; 890ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final int COL_SCORE = 3; 891ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 892ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = db.query(Tables.DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES, PROJ_PRIMARY, 893ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey AggregatesColumns.CONCRETE_ID + "=" + aggId + " AND " + DataColumns.MIMETYPE_ID 894ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "=" + mimeId, null, null, null, SCORE); 895ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 896ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (fixOptimal) { 897ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String colId = null; 898ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String colPackageId = null; 899ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 900ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID; 901ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colPackageId = AggregatesColumns.OPTIMAL_PRIMARY_PHONE_PACKAGE_ID; 902ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 903ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID; 904ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colPackageId = AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_PACKAGE_ID; 905ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 906ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 907ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Start by replacing with null, since fixOptimal told us that 908ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // the previous aggregate values are bad. 909ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.putNull(colId); 910ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.putNull(colPackageId); 911ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 912ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // When finding a new optimal primary, we only care about the 913ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // highest scoring value, regardless of source. 914ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (cursor.moveToFirst()) { 915ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long newOptimal = cursor.getLong(COL_DATA_ID); 916ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long newOptimalPackage = cursor.getLong(COL_PACKAGE_ID); 917ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 918ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (newOptimal != 0) { 919ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.put(colId, newOptimal); 920ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 921ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (newOptimalPackage != 0) { 922ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.put(colPackageId, newOptimalPackage); 923ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 924ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 925ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 926ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 927ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (fixFallback) { 928ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String colId = null; 929ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (mimeId == mimePhone) { 930ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID; 931ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } else if (mimeId == mimeEmail) { 932ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey colId = AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID; 933ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 934ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 935ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Start by replacing with null, since fixFallback told us that 936ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // the previous aggregate values are bad. 937ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.putNull(colId); 938ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 939ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // The best fallback value is the highest scoring data item that 940ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // hasn't been restricted. 941ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor.moveToPosition(-1); 942ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey while (cursor.moveToNext()) { 943ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final boolean isRestricted = (cursor.getInt(COL_IS_RESTRICTED) == 1); 944ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (!isRestricted) { 945ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey values.put(colId, cursor.getLong(COL_DATA_ID)); 946ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 947ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 948ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 949ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 950ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 951ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Push through any aggregate updates we have 952ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (values.size() > 0) { 953ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey db.update(Tables.AGGREGATES, values, AggregatesColumns.CONCRETE_ID + "=" + aggId, 954ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey null); 955ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 956ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 957ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 958ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return dataDeleted; 959ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 960ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 961ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 9624097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov * Parse the supplied display name, but only if the incoming values do not already contain 9634097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov * structured name parts. 9644097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov */ 9654097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private void parseStructuredName(ContentValues values) { 9664097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov final String fullName = values.getAsString(StructuredName.DISPLAY_NAME); 9674097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov if (TextUtils.isEmpty(fullName) 9684097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov || !TextUtils.isEmpty(values.getAsString(StructuredName.PREFIX)) 9694097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov || !TextUtils.isEmpty(values.getAsString(StructuredName.GIVEN_NAME)) 9704097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov || !TextUtils.isEmpty(values.getAsString(StructuredName.MIDDLE_NAME)) 9714097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov || !TextUtils.isEmpty(values.getAsString(StructuredName.FAMILY_NAME)) 9724097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov || !TextUtils.isEmpty(values.getAsString(StructuredName.SUFFIX))) { 9734097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov return; 9744097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov } 9754097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 9764097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov NameSplitter.Name name = new NameSplitter.Name(); 9774097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov mNameSplitter.split(name, fullName); 9784097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 9794097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov values.put(StructuredName.PREFIX, name.getPrefix()); 9804097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov values.put(StructuredName.GIVEN_NAME, name.getGivenNames()); 9814097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov values.put(StructuredName.MIDDLE_NAME, name.getMiddleName()); 9824097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov values.put(StructuredName.FAMILY_NAME, name.getFamilyName()); 9834097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov values.put(StructuredName.SUFFIX, name.getSuffix()); 9844097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov } 9854097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 9864097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov /** 987ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 988ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 989ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private long insertGroup(ContentValues values, Account account) { 990ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 991ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 992ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ContentValues overriddenValues = new ContentValues(values); 993ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (!resolveAccount(overriddenValues, account)) { 994ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return -1; 995ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 996ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 997ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 998ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final String packageName = overriddenValues.getAsString(Groups.PACKAGE); 999ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey overriddenValues.put(Groups.PACKAGE_ID, mOpenHelper.getPackageId(packageName)); 1000ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey overriddenValues.remove(Groups.PACKAGE); 1001ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1002ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return db.insert(Tables.GROUPS, Groups.TITLE, overriddenValues); 1003ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1004ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1005ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 10061f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey * Inserts a presence update. 10071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 10081f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private long insertPresence(ContentValues values) { 10091f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 10101f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final String handle = values.getAsString(Presence.IM_HANDLE); 10111f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final String protocol = values.getAsString(Presence.IM_PROTOCOL); 10121f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (TextUtils.isEmpty(handle) || TextUtils.isEmpty(protocol)) { 10131f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey throw new IllegalArgumentException("IM_PROTOCOL and IM_HANDLE are required"); 10141f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 10151f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 10161f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // TODO: generalize to allow other providers to match against email 10171f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey boolean matchEmail = GTALK_PROTOCOL_STRING.equals(protocol); 10181f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 10191f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String selection; 10201f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String[] selectionArgs; 10211f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (matchEmail) { 10221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey selection = "(" + Clauses.WHERE_IM_MATCHES + ") OR (" + Clauses.WHERE_EMAIL_MATCHES + ")"; 10231f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey selectionArgs = new String[] { protocol, handle, handle }; 10241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 10251f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey selection = Clauses.WHERE_IM_MATCHES; 10261f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey selectionArgs = new String[] { protocol, handle }; 10271f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 10281f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 10291f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey long dataId = -1; 10301f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey long aggId = -1; 10311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 10321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 1033ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = db.query(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES, 1034ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Projections.PROJ_DATA_CONTACTS, selection, selectionArgs, null, null, null); 10351f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 1036ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey dataId = cursor.getLong(Projections.COL_DATA_ID); 1037ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey aggId = cursor.getLong(Projections.COL_AGGREGATE_ID); 10381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 10391f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 10401f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 10411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 10421f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 104331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 104431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 104531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 10461f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 10471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 10481f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey values.put(Presence.DATA_ID, dataId); 10491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey values.put(Presence.AGGREGATE_ID, aggId); 10501f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 10511f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // Insert the presence update 10521f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey long presenceId = db.replace(Tables.PRESENCE, null, values); 10531f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return presenceId; 10541f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 10551f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 10564f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 10574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public int delete(Uri uri, String selection, String[] selectionArgs) { 1058508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1059508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 1060508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 106135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 106235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana return mOpenHelper.getSyncState().delete(db, selection, selectionArgs); 106335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 10646bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES_ID: { 10656bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov long aggregateId = ContentUris.parseId(uri); 10666bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 10676bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov // Remove references to the aggregate first 10686bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov ContentValues values = new ContentValues(); 10696bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov values.putNull(Contacts.AGGREGATE_ID); 1070b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.update(Tables.CONTACTS, values, Contacts.AGGREGATE_ID + "=" + aggregateId, null); 10716bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 1072b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return db.delete(Tables.AGGREGATES, BaseColumns._ID + "=" + aggregateId, null); 10736bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 10746bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 1075508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case CONTACTS_ID: { 1076508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long contactId = ContentUris.parseId(uri); 1077b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey int contactsDeleted = db.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null); 1078b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey int dataDeleted = db.delete(Tables.DATA, Data.CONTACT_ID + "=" + contactId, null); 1079508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey return contactsDeleted + dataDeleted; 1080508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 1081508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 1082508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: { 1083508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 1084ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return deleteData(dataId); 1085ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1086ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1087ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 1088ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 1089ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long groupMembershipMimetypeId = mOpenHelper 1090ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 1091ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey int groupsDeleted = db.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 1092ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey int dataDeleted = db.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 1093ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 1094ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + groupId, null); 1095ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mOpenHelper.updateAllVisible(); 1096ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return groupsDeleted + dataDeleted; 1097508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 1098508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 10991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case PRESENCE: { 11001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return db.delete(Tables.PRESENCE, null, null); 11011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 11021f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1103508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey default: 1104508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey throw new UnsupportedOperationException("Unknown uri: " + uri); 1105508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 11064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 11074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1108f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana private static Account readAccountFromQueryParams(Uri uri) { 1109035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String name = uri.getQueryParameter(Contacts.ACCOUNT_NAME); 1110035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String type = uri.getQueryParameter(Contacts.ACCOUNT_TYPE); 1111f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana if (TextUtils.isEmpty(name) || TextUtils.isEmpty(type)) { 1112f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana return null; 1113f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana } 1114f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana return new Account(name, type); 1115f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana } 1116f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana 1117ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 11184f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 11194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 112000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 112135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 112200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 112300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 112400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 112535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 112635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana return mOpenHelper.getSyncState().update(db, values, selection, selectionArgs); 112735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1128c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar // TODO(emillar): We will want to disallow editing the aggregates table at some point. 112900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar case AGGREGATES: { 113000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar count = db.update(Tables.AGGREGATES, values, selection, selectionArgs); 113100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 113200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 113300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 113400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar case AGGREGATES_ID: { 1135d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov count = updateAggregateData(db, ContentUris.parseId(uri), values); 1136c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 1137c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 1138c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1139c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar case DATA_ID: { 1140c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar boolean containsIsSuperPrimary = values.containsKey(Data.IS_SUPER_PRIMARY); 1141c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar boolean containsIsPrimary = values.containsKey(Data.IS_PRIMARY); 1142c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar final long id = ContentUris.parseId(uri); 1143c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1144c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar // Remove primary or super primary values being set to 0. This is disallowed by the 1145c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar // content provider. 11468b341f8ea85257c5f7103863405e0273921e16bcEvan Millar if (containsIsSuperPrimary && values.getAsInteger(Data.IS_SUPER_PRIMARY) == 0) { 1147c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar containsIsSuperPrimary = false; 1148c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar values.remove(Data.IS_SUPER_PRIMARY); 1149c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 11508b341f8ea85257c5f7103863405e0273921e16bcEvan Millar if (containsIsPrimary && values.getAsInteger(Data.IS_PRIMARY) == 0) { 1151c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar containsIsPrimary = false; 1152c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar values.remove(Data.IS_PRIMARY); 1153c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 1154c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1155c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar if (containsIsSuperPrimary) { 1156c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar setIsSuperPrimary(id); 1157c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar setIsPrimary(id); 1158c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1159c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar // Now that we've taken care of setting these, remove them from "values". 1160c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar values.remove(Data.IS_SUPER_PRIMARY); 1161c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar if (containsIsPrimary) { 1162c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar values.remove(Data.IS_PRIMARY); 1163c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 1164c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } else if (containsIsPrimary) { 1165c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar setIsPrimary(id); 1166c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1167c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar // Now that we've taken care of setting this, remove it from "values". 1168c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar values.remove(Data.IS_PRIMARY); 1169c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 1170c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1171c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar if (values.size() > 0) { 1172c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar String selectionWithId = (Data._ID + " = " + ContentUris.parseId(uri) + " ") 1173f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + (selection == null ? "" : " AND " + selection); 1174c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar count = db.update(Tables.DATA, values, selectionWithId, selectionArgs); 1175c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 117600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 117700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 11787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 11797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS: { 11807e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana count = db.update(Tables.CONTACTS, values, selection, selectionArgs); 11817e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 11827e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 11837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 11847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS_ID: { 11857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String selectionWithId = (Contacts._ID + " = " + ContentUris.parseId(uri) + " ") 11867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana + (selection == null ? "" : " AND " + selection); 11877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana count = db.update(Tables.CONTACTS, values, selectionWithId, selectionArgs); 11887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana Log.i(TAG, "Selection is: " + selectionWithId); 11897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 11907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 11917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 11927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case DATA: { 11937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana count = db.update(Tables.DATA, values, selection, selectionArgs); 11947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 11957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 11967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 1197ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 1198ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey count = db.update(Tables.GROUPS, values, selection, selectionArgs); 1199ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mOpenHelper.updateAllVisible(); 1200ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1201ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1202ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1203ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 1204ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 1205ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey String selectionWithId = (Groups._ID + "=" + groupId + " ") 1206ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + (selection == null ? "" : " AND " + selection); 1207ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey count = db.update(Tables.GROUPS, values, selectionWithId, selectionArgs); 1208ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1209ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // If changing visibility, then update aggregates 1210ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey if (values.containsKey(Groups.GROUP_VISIBLE)) { 1211ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mOpenHelper.updateAllVisible(); 1212ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1213ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1214ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1215ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1216ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1217127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 1218127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov count = updateAggregationException(db, values); 1219b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 1220b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1221b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 1222619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey case RESTRICTION_EXCEPTIONS: { 1223619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Enforce required fields 1224619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean hasFields = values.containsKey(RestrictionExceptions.PACKAGE_PROVIDER) 1225619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey && values.containsKey(RestrictionExceptions.PACKAGE_CLIENT) 1226619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey && values.containsKey(RestrictionExceptions.ALLOW_ACCESS); 1227619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (!hasFields) { 1228619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey throw new IllegalArgumentException("PACKAGE_PROVIDER, PACKAGE_CLIENT, and" 1229619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + "ALLOW_ACCESS are all required fields"); 1230619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1231619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1232619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String packageProvider = values 1233619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey .getAsString(RestrictionExceptions.PACKAGE_PROVIDER); 1234619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final boolean allowAccess = (values 1235619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey .getAsInteger(RestrictionExceptions.ALLOW_ACCESS) == 1); 1236619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1237619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final Context context = getContext(); 1238619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final PackageManager pm = context.getPackageManager(); 1239619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1240619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Enforce that caller has authority over the requested package 1241619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: move back to Binder.getCallingUid() when we can stub-out test suite 1242619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int callingUid = OpenHelper 1243619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey .getUidForPackageName(pm, context.getPackageName()); 1244619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String[] ownedPackages = pm.getPackagesForUid(callingUid); 1245619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (!isContained(ownedPackages, packageProvider)) { 1246619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey throw new RuntimeException( 1247619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey "Requested PACKAGE_PROVIDER doesn't belong to calling UID."); 1248619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1249619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1250619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Add or remove exception using exception helper 1251619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (allowAccess) { 1252619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey mOpenHelper.addRestrictionException(context, values); 1253619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } else { 1254619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey mOpenHelper.removeRestrictionException(context, values); 1255619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1256619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1257619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 1258619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1259619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 12607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana default: 1261f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.update(uri, values, selection, selectionArgs); 126200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 126300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 126400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar if (count > 0) { 126500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar getContext().getContentResolver().notifyChange(uri, null); 126600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 126700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 12684f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 12694f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1270d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov private int updateAggregateData(SQLiteDatabase db, long aggregateId, ContentValues values) { 1271d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1272d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // First update all constituent contacts 1273f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov ContentValues optionValues = new ContentValues(5); 1274f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov OpenHelper.copyStringValue(optionValues, Contacts.CUSTOM_RINGTONE, 1275f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov values, Aggregates.CUSTOM_RINGTONE); 1276f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov OpenHelper.copyLongValue(optionValues, Contacts.SEND_TO_VOICEMAIL, 1277f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov values, Aggregates.SEND_TO_VOICEMAIL); 1278f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov OpenHelper.copyLongValue(optionValues, Contacts.LAST_TIME_CONTACTED, 1279f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov values, Aggregates.LAST_TIME_CONTACTED); 1280f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov OpenHelper.copyLongValue(optionValues, Contacts.TIMES_CONTACTED, 1281f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov values, Aggregates.TIMES_CONTACTED); 1282f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov OpenHelper.copyLongValue(optionValues, Contacts.STARRED, 1283f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov values, Aggregates.STARRED); 1284d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1285d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 1286d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov if (optionValues.size() == 0) { 1287d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 1288d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1289d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1290f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov db.update(Tables.CONTACTS, optionValues, Contacts.AGGREGATE_ID + "=" + aggregateId, null); 1291f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return db.update(Tables.AGGREGATES, values, Aggregates._ID + "=" + aggregateId, null); 1292f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 1293d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1294f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov public void updateContactTime(long aggregateId, long lastTimeContacted) { 1295f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mLastTimeContactedUpdate.bindLong(1, lastTimeContacted); 1296f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mLastTimeContactedUpdate.bindLong(2, aggregateId); 1297f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mLastTimeContactedUpdate.execute(); 1298d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 1299d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 1300127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private static class ContactPair { 1301127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov final long contactId1; 1302127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov final long contactId2; 1303127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1304127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov /** 1305127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov * Constructor that ensures that this.contactId1 < this.contactId2 1306127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov */ 1307127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov public ContactPair(long contactId1, long contactId2) { 1308127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov if (contactId1 < contactId2) { 1309127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId1 = contactId1; 1310127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId2 = contactId2; 1311127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } else { 1312127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId2 = contactId1; 1313127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov this.contactId1 = contactId2; 1314127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1315127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1316127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 131780c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 1318127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 1319127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 1320127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov long aggregateId = values.getAsInteger(AggregationExceptions.AGGREGATE_ID); 1321127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov long contactId = values.getAsInteger(AggregationExceptions.CONTACT_ID); 132280c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 1323127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // First, we build a list of contactID-contactID pairs for the given aggregate and contact. 1324127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov ArrayList<ContactPair> pairs = new ArrayList<ContactPair>(); 1325ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Cursor c = db.query(Tables.CONTACTS, Projections.PROJ_CONTACTS, 1326127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov Contacts.AGGREGATE_ID + "=" + aggregateId, 1327127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov null, null, null, null); 1328127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov try { 1329127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov while (c.moveToNext()) { 1330ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long aggregatedContactId = c.getLong(Projections.COL_CONTACT_ID); 1331e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov if (aggregatedContactId != contactId) { 1332e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov pairs.add(new ContactPair(aggregatedContactId, contactId)); 1333e2e0ba75ce239f0f5481cdef9082daebf8fc2d35Dmitri Plotnikov } 1334b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1335b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } finally { 1336b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov c.close(); 1337b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1338127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1339127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // Now we iterate through all contact pairs to see if we need to insert/delete/update 1340127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // the corresponding exception 1341127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 1342127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 1343127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov for (ContactPair pair : pairs) { 1344127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov final String whereClause = 1345127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov AggregationExceptionColumns.CONTACT_ID1 + "=" + pair.contactId1 + " AND " 1346127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov + AggregationExceptionColumns.CONTACT_ID2 + "=" + pair.contactId2; 1347127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 1348127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, whereClause, null); 1349127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } else { 1350127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues.put(AggregationExceptionColumns.CONTACT_ID1, pair.contactId1); 1351127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues.put(AggregationExceptionColumns.CONTACT_ID2, pair.contactId2); 1352127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 1353127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov exceptionValues); 1354127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1355127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 1356127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1357f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov int aggregationMode = mContactAggregator.markContactForAggregation(contactId); 1358f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov if (aggregationMode != Contacts.AGGREGATION_MODE_DISABLED) { 1359f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mContactAggregator.aggregateContact(db, contactId); 1360f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC 1361f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov || exceptionType == AggregationExceptions.TYPE_KEEP_OUT) { 1362f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov mContactAggregator.updateAggregateData(aggregateId); 1363f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 13647a39bf269294a8130ddd463460b9b36cf4ff74a8Dmitri Plotnikov } 1365127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 1366127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 1367127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 1368127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 1369b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1370b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 1371619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1372619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Test if a {@link String} value appears in the given list. 1373619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1374619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private boolean isContained(String[] array, String value) { 1375bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar if (array != null) { 1376bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar for (String test : array) { 1377bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar if (value.equals(test)) { 1378bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar return true; 1379bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar } 1380619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1381619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1382619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return false; 1383619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1384619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1385619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1386619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Test if a {@link String} value appears in the given list, and add to the 1387619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * array if the value doesn't already appear. 1388619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1389619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private String[] assertContained(String[] array, String value) { 1390bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar if (array == null) { 1391bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar array = new String[] {value}; 1392bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar } else if (!isContained(array, value)) { 1393619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey String[] newArray = new String[array.length + 1]; 1394619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey System.arraycopy(array, 0, newArray, 0, array.length); 1395619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey newArray[array.length] = value; 1396619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey array = newArray; 1397619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1398619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return array; 1399619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1400619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 14014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 14024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 14034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 14044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 140535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1406d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 14071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 14081f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String limit = null; 1409bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar String aggregateIdColName = Tables.AGGREGATES + "." + Aggregates._ID; 14104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1411619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: Consider writing a test case for RestrictionExceptions when you 1412619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // write a new query() block to make sure it protects restricted data. 1413a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 14144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 141535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 141635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana return mOpenHelper.getSyncState().query(db, projection, selection, selectionArgs, 141735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana sortOrder); 141835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 14196bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES: { 1420b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey qb.setTables(Tables.AGGREGATES); 1421619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1422619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesProjectionMap); 1423619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.setProjectionMap(sAggregatesProjectionMap); 1424619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 1425619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1426619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1427619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey case AGGREGATES_ID: { 1428619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long aggId = ContentUris.parseId(uri); 1429619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.setTables(Tables.AGGREGATES); 1430ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(AggregatesColumns.CONCRETE_ID + "=" + aggId + " AND "); 1431619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1432619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesProjectionMap); 14336bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov qb.setProjectionMap(sAggregatesProjectionMap); 14346bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 14356bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 14366bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 14371f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case AGGREGATES_SUMMARY: { 1438619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: join into social status tables 14391f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1440619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1441619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesSummaryProjectionMap); 1442619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection = assertContained(projection, Aggregates.PRIMARY_PHONE_ID); 14431f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1444bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy = aggregateIdColName; 14451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 14461f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 14471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 14481f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey case AGGREGATES_SUMMARY_ID: { 1449619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: join into social status tables 14501f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey long aggId = ContentUris.parseId(uri); 14511f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1452ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(AggregatesColumns.CONCRETE_ID + "=" + aggId + " AND "); 1453619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregateRestrictionExceptions(qb); 1454619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyAggregatePrimaryRestrictionExceptions(sAggregatesSummaryProjectionMap); 1455619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection = assertContained(projection, Aggregates.PRIMARY_PHONE_ID); 14561f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1457bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy = aggregateIdColName; 14581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 14591f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 14601f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1461ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case AGGREGATES_SUMMARY_FILTER: { 1462619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: filter query based on callingUid 1463ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1464ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1465ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 1466ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(buildAggregateLookupWhereClause(uri.getLastPathSegment())); 1467ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1468bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy = aggregateIdColName; 1469ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 1470ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1471ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 1472d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar case AGGREGATES_SUMMARY_STREQUENT_FILTER: 1473d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar case AGGREGATES_SUMMARY_STREQUENT: { 1474d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Build the first query for starred 1475d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1476d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1477d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar if (match == AGGREGATES_SUMMARY_STREQUENT_FILTER 1478d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar && uri.getPathSegments().size() > 3) { 1479d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.appendWhere(buildAggregateLookupWhereClause(uri.getLastPathSegment())); 1480d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 1481d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar final String starredQuery = qb.buildQuery(projection, Aggregates.STARRED + "=1", 1482bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar null, aggregateIdColName, null, null, 1483d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar null /* limit */); 1484d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 1485d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Build the second query for frequent 1486d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 1487d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1488d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1489d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar if (match == AGGREGATES_SUMMARY_STREQUENT_FILTER 1490d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar && uri.getPathSegments().size() > 3) { 1491d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb.appendWhere(buildAggregateLookupWhereClause(uri.getLastPathSegment())); 1492d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 1493d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar final String frequentQuery = qb.buildQuery(projection, 1494d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar Aggregates.TIMES_CONTACTED + " > 0 AND (" + Aggregates.STARRED 1495d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar + " = 0 OR " + Aggregates.STARRED + " IS NULL)", 1496bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar null, aggregateIdColName, null, null, null); 1497d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 1498d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 1499d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, 1500d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar STREQUENT_ORDER_BY, STREQUENT_LIMIT); 1501d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar Cursor c = db.rawQueryWithFactory(null, query, null, 1502d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1503d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 1504d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar if ((c != null) && !isTemporary()) { 1505d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar c.setNotificationUri(getContext().getContentResolver(), 1506d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 1507d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 1508d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar return c; 1509d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 1510d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 1511b67163a1088f09c59f324350662eb18772fac6b6Evan Millar case AGGREGATES_SUMMARY_GROUP: { 1512b67163a1088f09c59f324350662eb18772fac6b6Evan Millar qb.setTables(Tables.AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE); 1513b67163a1088f09c59f324350662eb18772fac6b6Evan Millar applyAggregateRestrictionExceptions(qb); 1514b67163a1088f09c59f324350662eb18772fac6b6Evan Millar applyAggregatePrimaryRestrictionExceptions(sAggregatesSummaryProjectionMap); 1515b67163a1088f09c59f324350662eb18772fac6b6Evan Millar projection = assertContained(projection, Aggregates.PRIMARY_PHONE_ID); 1516b67163a1088f09c59f324350662eb18772fac6b6Evan Millar qb.setProjectionMap(sAggregatesSummaryProjectionMap); 1517b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (uri.getPathSegments().size() > 2) { 1518b67163a1088f09c59f324350662eb18772fac6b6Evan Millar qb.appendWhere(" AND " + sAggregatesInGroupSelect); 1519b67163a1088f09c59f324350662eb18772fac6b6Evan Millar selectionArgs = appendGroupArg(selectionArgs, uri.getLastPathSegment()); 1520b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 1521b67163a1088f09c59f324350662eb18772fac6b6Evan Millar groupBy = aggregateIdColName; 1522b67163a1088f09c59f324350662eb18772fac6b6Evan Millar break; 1523b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 1524b67163a1088f09c59f324350662eb18772fac6b6Evan Millar 15256bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES_DATA: { 1526619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long aggId = Long.parseLong(uri.getPathSegments().get(1)); 15279261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES_GROUPS); 15289261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setProjectionMap(sDataContactsGroupsAggregateProjectionMap); 1529619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(Contacts.AGGREGATE_ID + "=" + aggId + " AND "); 1530619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 15316bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 15326bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 153300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 1534ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES_FILTER: { 1535ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES); 1536ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sDataContactsAggregateProjectionMap); 1537ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 1538ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 1539ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(" AND " + buildAggregateLookupWhereClause( 1540ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar uri.getLastPathSegment())); 1541ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1542ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 1543ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1544ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1545ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES: { 1546ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES); 1547ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sDataContactsAggregateProjectionMap); 1548ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(Data.MIMETYPE + " = \"" + Phone.CONTENT_ITEM_TYPE + "\""); 1549ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 1550ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1551ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 1552ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 1553ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES); 1554ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.setProjectionMap(sDataContactsAggregateProjectionMap); 1555ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar qb.appendWhere(Data.MIMETYPE + " = \"" + Postal.CONTENT_ITEM_TYPE + "\""); 1556ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 1557ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 1558ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 15594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS: { 1560035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana qb.setTables(Tables.CONTACTS_JOIN_PACKAGES); 15614f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton qb.setProjectionMap(sContactsProjectionMap); 1562619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyContactsRestrictionExceptions(qb); 15634f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 15644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 15654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 15664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS_ID: { 1567619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long contactId = ContentUris.parseId(uri); 1568035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana qb.setTables(Tables.CONTACTS_JOIN_PACKAGES); 15694f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton qb.setProjectionMap(sContactsProjectionMap); 1570ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(ContactsColumns.CONCRETE_ID + "=" + contactId + " AND "); 1571619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyContactsRestrictionExceptions(qb); 15724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 15734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 15744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1575a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case CONTACTS_DATA: { 1576619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long contactId = Long.parseLong(uri.getPathSegments().get(1)); 15779261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_GROUPS); 15789261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setProjectionMap(sDataContactsGroupsProjectionMap); 1579619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(Data.CONTACT_ID + "=" + contactId + " AND "); 1580619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 1581a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 1582a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1583a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 158428ab0f857caa92402878244d9c5ea2a59e070935Jeff Sharkey case CONTACTS_FILTER_EMAIL: { 1585619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: filter query based on callingUid 1586ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES); 1587e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey qb.setProjectionMap(sDataContactsProjectionMap); 15885d0f923eb4c5351ebf323cc6f19c82acff98693eJeff Sharkey qb.appendWhere(Data.MIMETYPE + "='" + CommonDataKinds.Email.CONTENT_ITEM_TYPE + "'"); 1589e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey qb.appendWhere(" AND " + CommonDataKinds.Email.DATA + "="); 1590e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey qb.appendWhereEscapeString(uri.getPathSegments().get(2)); 1591e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 1592e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 1593e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 1594e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey case DATA: { 1595035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountName = uri.getQueryParameter(Contacts.ACCOUNT_NAME); 1596035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountType = uri.getQueryParameter(Contacts.ACCOUNT_TYPE); 1597343c56b5679c58bf1835a0e219fff57beae6ecefFred Quintana if (!TextUtils.isEmpty(accountName)) { 1598035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana qb.appendWhere(Contacts.ACCOUNT_NAME + "=" 1599035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountName) + " AND " 1600035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + Contacts.ACCOUNT_TYPE + "=" 1601035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountType) + " AND "); 1602343c56b5679c58bf1835a0e219fff57beae6ecefFred Quintana } 16039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_GROUPS); 16049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setProjectionMap(sDataGroupsProjectionMap); 1605619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 1606e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 1607e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 1608e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 16094f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case DATA_ID: { 16109261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_GROUPS); 16119261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setProjectionMap(sDataGroupsProjectionMap); 1612ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(DataColumns.CONCRETE_ID + "=" + ContentUris.parseId(uri) + " AND "); 1613619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyDataRestrictionExceptions(qb); 16144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 16154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 16164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1617a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 1618619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: filter query based on callingUid 1619a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton if (TextUtils.isEmpty(sortOrder)) { 1620a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // Default the sort order to something reasonable so we get consistent 1621a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // results when callers don't request an ordering 1622e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey sortOrder = Data.CONTACT_ID; 1623a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1624a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1625a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final String number = uri.getLastPathSegment(); 1626bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov OpenHelper.buildPhoneLookupQuery(qb, number); 1627a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton qb.setProjectionMap(sDataContactsProjectionMap); 1628a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 1629a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 1630a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 1631ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 1632ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.GROUPS_JOIN_PACKAGES); 1633ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 1634ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1635ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1636ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1637ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 1638ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 1639ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.GROUPS_JOIN_PACKAGES); 1640ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 1641ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.appendWhere(GroupsColumns.CONCRETE_ID + "=" + groupId); 1642ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1643ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1644ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1645ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 1646ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setTables(Tables.GROUPS_JOIN_PACKAGES_DATA_CONTACTS_AGGREGATES); 1647ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsSummaryProjectionMap); 1648ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey groupBy = GroupsColumns.CONCRETE_ID; 1649ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 1650ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 1651ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 1652b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 1653127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS_JOIN_CONTACTS); 1654b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 1655b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 1656b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 1657b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 165831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 165931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov long aggregateId = Long.parseLong(uri.getPathSegments().get(1)); 166031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final String maxSuggestionsParam = 166131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov uri.getQueryParameter(AggregationSuggestions.MAX_SUGGESTIONS); 166231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 166331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 166431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (maxSuggestionsParam != null) { 166531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = Integer.parseInt(maxSuggestionsParam); 166631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 166731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 166831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 166931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 167031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov return mContactAggregator.queryAggregationSuggestions(aggregateId, projection, 167131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov sAggregatesProjectionMap, maxSuggestions); 167231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 167331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1674619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey case RESTRICTION_EXCEPTIONS: { 1675619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.setTables(Tables.RESTRICTION_EXCEPTIONS); 1676619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.setProjectionMap(sRestrictionExceptionsProjectionMap); 1677619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 1678619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1679619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 16804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 1681f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.query(uri, projection, selection, selectionArgs, 1682f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov sortOrder); 16834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 16844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 16854f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Perform the query and set the notification uri 16861f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final Cursor c = qb.query(db, projection, selection, selectionArgs, 1687bc5c799a52b5bde2f273efd118ebe2228c3d8f15Evan Millar groupBy, null, sortOrder, limit); 16884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 16894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 16904f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 16914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 16924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 16934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 16947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 1695619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Restrict selection of {@link Aggregates} to only public ones, or those 1696619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * the caller has been granted a {@link RestrictionExceptions} to. 1697619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1698619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private void applyAggregateRestrictionExceptions(SQLiteQueryBuilder qb) { 1699619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int clientUid = OpenHelper.getUidForPackageName(getContext().getPackageManager(), 1700619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey getContext().getPackageName()); 1701619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1702619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere("(" + AggregatesColumns.SINGLE_RESTRICTED_PACKAGE_ID + " IS NULL"); 1703619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String exceptionClause = mOpenHelper.getRestrictionExceptionClause(clientUid, 1704619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.SINGLE_RESTRICTED_PACKAGE_ID); 1705619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (exceptionClause != null) { 1706619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(" OR (" + exceptionClause + ")"); 1707619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1708619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(")"); 1709619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1710619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1711619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1712619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Find any exceptions that have been granted to the calling process, and 1713619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * add projections to correctly select {@link Aggregates#PRIMARY_PHONE_ID} 1714619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * and {@link Aggregates#PRIMARY_EMAIL_ID}. 1715619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1716619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private void applyAggregatePrimaryRestrictionExceptions(HashMap<String, String> projection) { 1717619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: move back to Binder.getCallingUid() when we can stub-out test suite 1718619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int clientUid = OpenHelper.getUidForPackageName(getContext().getPackageManager(), 1719619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey getContext().getPackageName()); 1720619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1721619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String projectionPhone = "(CASE WHEN " 1722619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + mOpenHelper.getRestrictionExceptionClause(clientUid, 1723619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_PHONE_PACKAGE_ID) + " THEN " 1724619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID + " ELSE " 1725619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID + " END) AS " 1726619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + Aggregates.PRIMARY_PHONE_ID; 1727619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.remove(Aggregates.PRIMARY_PHONE_ID); 1728619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.put(Aggregates.PRIMARY_PHONE_ID, projectionPhone); 1729619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1730619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String projectionEmail = "(CASE WHEN " 1731619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + mOpenHelper.getRestrictionExceptionClause(clientUid, 1732619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_PACKAGE_ID) + " THEN " 1733619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID + " ELSE " 1734619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID + " END) AS " 1735619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + Aggregates.PRIMARY_EMAIL_ID; 1736619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.remove(Aggregates.PRIMARY_EMAIL_ID); 1737619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey projection.put(Aggregates.PRIMARY_EMAIL_ID, projectionEmail); 1738619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1739619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1740619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1741619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Find any exceptions that have been granted to the 1742619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link Binder#getCallingUid()}, and add a limiting clause to the given 1743619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link SQLiteQueryBuilder} to hide restricted data. 1744619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1745619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private void applyContactsRestrictionExceptions(SQLiteQueryBuilder qb) { 1746619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // TODO: move back to Binder.getCallingUid() when we can stub-out test suite 1747619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int clientUid = OpenHelper.getUidForPackageName(getContext().getPackageManager(), 1748619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey getContext().getPackageName()); 1749619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1750619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere("(" + Contacts.IS_RESTRICTED + "=0"); 1751619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String exceptionClause = mOpenHelper.getRestrictionExceptionClause(clientUid, 17529261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana OpenHelper.ContactsColumns.CONCRETE_PACKAGE_ID); 1753619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (exceptionClause != null) { 1754619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(" OR (" + exceptionClause + ")"); 1755619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1756619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey qb.appendWhere(")"); 1757619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1758619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1759619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1760619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Find any exceptions that have been granted to the 1761619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link Binder#getCallingUid()}, and add a limiting clause to the given 1762619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * {@link SQLiteQueryBuilder} to hide restricted data. 1763619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1764619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private void applyDataRestrictionExceptions(SQLiteQueryBuilder qb) { 1765619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey applyContactsRestrictionExceptions(qb); 1766619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1767619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1768619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 17697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana * An implementation of EntityIterator that joins the contacts and data tables 17707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana * and consumes all the data rows for a contact in order to build the Entity for a contact. 17717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 17727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private static class ContactsEntityIterator implements EntityIterator { 17737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private final Cursor mEntityCursor; 17747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private volatile boolean mIsClosed; 17757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17767e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private static final String[] DATA_KEYS = new String[]{ 17777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data1", 17787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data2", 17797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data3", 17807e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data4", 17817e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data5", 17827e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data6", 17837e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data7", 17847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data8", 17857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data9", 17867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana "data10"}; 17877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 17887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana private static final String[] PROJECTION = new String[]{ 1789035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.ACCOUNT_NAME, 1790035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.ACCOUNT_TYPE, 1791035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.SOURCE_ID, 1792035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.VERSION, 1793035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.DIRTY, 1794035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data._ID, 1795035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.MIMETYPE, 1796035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA1, 1797035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA2, 1798035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA3, 1799035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA4, 1800035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA5, 1801035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA6, 1802035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA7, 1803035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA8, 1804035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA9, 1805035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.DATA10, 1806035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.CONTACT_ID, 1807035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.Data.IS_PRIMARY, 18089261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana Contacts.Data.DATA_VERSION, 18099261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana GroupMembership.GROUP_SOURCE_ID}; 1810035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana 1811035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_ACCOUNT_NAME = 0; 1812035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_ACCOUNT_TYPE = 1; 1813035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_SOURCE_ID = 2; 1814035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_VERSION = 3; 1815035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_DIRTY = 4; 1816035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_DATA_ID = 5; 1817035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_MIMETYPE = 6; 1818035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_DATA1 = 7; 1819035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_CONTACT_ID = 17; 1820035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_IS_PRIMARY = 18; 1821035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int COLUMN_DATA_VERSION = 19; 18229261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana private static final int COLUMN_GROUP_SOURCE_ID = 20; 18237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public ContactsEntityIterator(ContactsProvider2 provider, String contactsIdString, Uri uri, 18257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String selection, String[] selectionArgs, String sortOrder) { 18267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mIsClosed = false; 18277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final String updatedSortOrder = (sortOrder == null) 18297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ? Contacts.Data.CONTACT_ID 18307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana : (Contacts.Data.CONTACT_ID + "," + sortOrder); 18317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteDatabase db = provider.mOpenHelper.getReadableDatabase(); 18337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 18349261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setTables(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_GROUPS); 18359261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana qb.setProjectionMap(sDataContactsGroupsProjectionMap); 18367e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (contactsIdString != null) { 18377e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana qb.appendWhere(Data.CONTACT_ID + "=" + contactsIdString); 18387e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 1839035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountName = uri.getQueryParameter(Contacts.ACCOUNT_NAME); 1840035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana final String accountType = uri.getQueryParameter(Contacts.ACCOUNT_TYPE); 1841035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana if (!TextUtils.isEmpty(accountName)) { 1842035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana qb.appendWhere(Contacts.ACCOUNT_NAME + "=" 1843035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountName) + " AND " 1844035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + Contacts.ACCOUNT_TYPE + "=" 1845035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + DatabaseUtils.sqlEscapeString(accountType)); 1846035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 18477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs, 18487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana null, null, updatedSortOrder); 18497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mEntityCursor.moveToFirst(); 18507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 18517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public void close() { 18537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (mIsClosed) { 18547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("closing when already closed"); 18557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 18567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mIsClosed = true; 18577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana mEntityCursor.close(); 18587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 18597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public boolean hasNext() throws RemoteException { 18617e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (mIsClosed) { 18627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("calling hasNext() when the iterator is closed"); 18637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 18647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return !mEntityCursor.isAfterLast(); 18667e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 18677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public Entity next() throws RemoteException { 18697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (mIsClosed) { 18707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("calling next() when the iterator is closed"); 18717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 18727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (!hasNext()) { 18737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new IllegalStateException("you may only call next() if hasNext() is true"); 18747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 18757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18767e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteCursor c = (SQLiteCursor) mEntityCursor; 18777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final long contactId = c.getLong(COLUMN_CONTACT_ID); 18797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18807e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // we expect the cursor is already at the row we need to read from 18817e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ContentValues contactValues = new ContentValues(); 1882035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana contactValues.put(Contacts.ACCOUNT_NAME, c.getString(COLUMN_ACCOUNT_NAME)); 1883035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana contactValues.put(Contacts.ACCOUNT_TYPE, c.getString(COLUMN_ACCOUNT_TYPE)); 18847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactValues.put(Contacts._ID, contactId); 18857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactValues.put(Contacts.DIRTY, c.getLong(COLUMN_DIRTY)); 1886f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana contactValues.put(Contacts.VERSION, c.getLong(COLUMN_VERSION)); 18877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactValues.put(Contacts.SOURCE_ID, c.getString(COLUMN_SOURCE_ID)); 18887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana Entity contact = new Entity(contactValues); 18897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 18907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // read data rows until the contact id changes 18917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana do { 18927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (contactId != c.getLong(COLUMN_CONTACT_ID)) { 18937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 18947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 18957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // add the data to to the contact 18967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ContentValues dataValues = new ContentValues(); 18977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(Contacts.Data._ID, c.getString(COLUMN_DATA_ID)); 1898f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana dataValues.put(Contacts.Data.MIMETYPE, c.getString(COLUMN_MIMETYPE)); 1899f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana dataValues.put(Contacts.Data.IS_PRIMARY, c.getString(COLUMN_IS_PRIMARY)); 1900f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana dataValues.put(Contacts.Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION)); 19019261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana if (!c.isNull(COLUMN_GROUP_SOURCE_ID)) { 19029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana dataValues.put(GroupMembership.GROUP_SOURCE_ID, 19039261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana c.getString(COLUMN_GROUP_SOURCE_ID)); 19049261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana } 19059261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana dataValues.put(Contacts.Data.DATA_VERSION, c.getLong(COLUMN_DATA_VERSION)); 19067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana for (int i = 0; i < 10; i++) { 19077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final int columnIndex = i + COLUMN_DATA1; 19087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String key = DATA_KEYS[i]; 19097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (c.isNull(columnIndex)) { 19107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana // don't put anything 19117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isLong(columnIndex)) { 19127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getLong(columnIndex)); 19137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isFloat(columnIndex)) { 19147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getFloat(columnIndex)); 19157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isString(columnIndex)) { 19167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getString(columnIndex)); 19177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } else if (c.isBlob(columnIndex)) { 19187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana dataValues.put(key, c.getBlob(columnIndex)); 19197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 19207e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 19217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contact.addSubValue(Data.CONTENT_URI, dataValues); 19227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } while (mEntityCursor.moveToNext()); 19237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 19247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return contact; 19257e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 19267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 19277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 1928a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov @Override 19297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs, 19307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String sortOrder) { 19317e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final int match = sUriMatcher.match(uri); 19327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana switch (match) { 19337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS: 19347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana case CONTACTS_ID: 19357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana String contactsIdString = null; 19367e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (match == CONTACTS_ID) { 19377e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana contactsIdString = uri.getPathSegments().get(1); 19387e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 19397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 19407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return new ContactsEntityIterator(this, contactsIdString, 19417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana uri, selection, selectionArgs, sortOrder); 19427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana default: 19437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throw new UnsupportedOperationException("Unknown uri: " + uri); 19447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 19457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 19467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 19474f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 19484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 1949a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 19504f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 19516bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES: return Aggregates.CONTENT_TYPE; 19526bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov case AGGREGATES_ID: return Aggregates.CONTENT_ITEM_TYPE; 19534f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS: return Contacts.CONTENT_TYPE; 19544f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case CONTACTS_ID: return Contacts.CONTENT_ITEM_TYPE; 1955508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 19566bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 1957508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 1958b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return mOpenHelper.getDataMimeType(dataId); 195931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: return AggregationExceptions.CONTENT_TYPE; 196031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_EXCEPTION_ID: return AggregationExceptions.CONTENT_ITEM_TYPE; 196131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: return Aggregates.CONTENT_TYPE; 19624f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 1963a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton throw new UnsupportedOperationException("Unknown uri: " + uri); 19644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 19657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 1966b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov @Override 19677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 19687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana throws OperationApplicationException { 19697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 19707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 19717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana db.beginTransaction(); 19727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana try { 19737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana ContentProviderResult[] results = super.applyBatch(operations); 19747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana db.setTransactionSuccessful(); 19757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return results; 19767e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } finally { 19777e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana db.endTransaction(); 19787e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 19797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 1980c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1981c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /* 1982c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * Sets the given dataId record in the "data" table to primary, and resets all data records of 1983c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * the same mimetype and under the same contact to not be primary. 1984c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * 1985c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * @param dataId the id of the data record to be set to primary. 1986c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar */ 1987c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private void setIsPrimary(long dataId) { 1988c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.bindLong(1, dataId); 1989c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.bindLong(2, dataId); 1990c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.bindLong(3, dataId); 1991c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetPrimaryStatement.execute(); 1992c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 1993c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 1994c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar /* 1995c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * Sets the given dataId record in the "data" table to "super primary", and resets all data 1996c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * records of the same mimetype and under the same aggregate to not be "super primary". 1997c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * 1998c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar * @param dataId the id of the data record to be set to primary. 1999c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar */ 2000c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar private void setIsSuperPrimary(long dataId) { 2001c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.bindLong(1, dataId); 2002c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.bindLong(2, dataId); 2003c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.bindLong(3, dataId); 2004c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar mSetSuperPrimaryStatement.execute(); 2005619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2006619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Find the parent aggregate and package for this new primary 2007619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 2008619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2009619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long aggId = -1; 2010619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey long packageId = -1; 2011619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean isRestricted = false; 2012619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey String mimeType = null; 2013619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2014619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey Cursor cursor = null; 2015619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey try { 2016ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey cursor = db.query(Tables.DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES, 2017ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Projections.PROJ_DATA_CONTACTS, DataColumns.CONCRETE_ID + "=" + dataId, null, 2018ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey null, null, null); 2019619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (cursor.moveToFirst()) { 2020ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey aggId = cursor.getLong(Projections.COL_AGGREGATE_ID); 2021ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey packageId = cursor.getLong(Projections.COL_PACKAGE_ID); 2022ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey isRestricted = (cursor.getInt(Projections.COL_IS_RESTRICTED) == 1); 2023ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mimeType = cursor.getString(Projections.COL_MIMETYPE); 2024619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2025619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } finally { 2026619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (cursor != null) { 2027619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey cursor.close(); 2028619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2029619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2030619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2031619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Bypass aggregate update if no parent found, or if we don't keep track 2032619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // of super-primary for this mimetype. 2033d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov if (aggId == -1) { 2034d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return; 2035d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 2036619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2037619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean isPhone = CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mimeType); 2038619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean isEmail = CommonDataKinds.Email.CONTENT_ITEM_TYPE.equals(mimeType); 2039619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2040619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Record this value as the new primary for the parent aggregate 2041619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final ContentValues values = new ContentValues(); 2042619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (isPhone) { 2043619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID, dataId); 2044619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_PHONE_PACKAGE_ID, packageId); 2045619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } else if (isEmail) { 2046619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID, dataId); 2047619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_PACKAGE_ID, packageId); 2048619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2049619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2050619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // If this data is unrestricted, then also set as fallback 2051619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (!isRestricted && isPhone) { 2052619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID, dataId); 2053619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } else if (!isRestricted && isEmail) { 2054619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID, dataId); 2055619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2056619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2057619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Push update into aggregates table, if needed 2058619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (values.size() > 0) { 2059619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey db.update(Tables.AGGREGATES, values, Aggregates._ID + "=" + aggId, null); 2060619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 2061619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2062c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 2063ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 2064ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private String buildAggregateLookupWhereClause(String filterParam) { 2065ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar StringBuilder filter = new StringBuilder(); 2066ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Tables.AGGREGATES); 2067ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append("."); 2068ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Aggregates._ID); 2069ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(" IN (SELECT "); 2070ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Contacts.AGGREGATE_ID); 2071ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(" FROM "); 2072ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Tables.CONTACTS); 2073ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(" WHERE "); 2074ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar filter.append(Contacts._ID); 2075d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar filter.append(" IN (SELECT contact_id FROM name_lookup WHERE normalized_name GLOB '"); 2076ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar // NOTE: Query parameters won't work here since the SQL compiler 2077ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar // needs to parse the actual string to know that it can use the 2078ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar // index to do a prefix scan. 2079d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar filter.append(NameNormalizer.normalize(filterParam) + "*"); 2080d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar filter.append("'))"); 2081ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar return filter.toString(); 2082ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 2083ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 2084b67163a1088f09c59f324350662eb18772fac6b6Evan Millar private String[] appendGroupArg(String[] selectionArgs, String arg) { 2085b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (selectionArgs == null) { 2086b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return new String[] {arg}; 2087b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } else { 2088b67163a1088f09c59f324350662eb18772fac6b6Evan Millar int newLength = selectionArgs.length + 1; 2089b67163a1088f09c59f324350662eb18772fac6b6Evan Millar String[] newSelectionArgs = new String[newLength]; 2090b67163a1088f09c59f324350662eb18772fac6b6Evan Millar System.arraycopy(selectionArgs, 0, newSelectionArgs, 0, selectionArgs.length); 2091b67163a1088f09c59f324350662eb18772fac6b6Evan Millar newSelectionArgs[newLength - 1] = arg; 2092b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return newSelectionArgs; 2093b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 2094b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 20954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 2096