ContactsDatabaseHelper.java revision 35ed95769096bb5dd406ad7d1fcaa49a0e35a307
1b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey/* 2b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * Copyright (C) 2009 The Android Open Source Project 3b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * 4b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 5b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * you may not use this file except in compliance with the License. 6b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * You may obtain a copy of the License at 7b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * 8b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 9b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * 10b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * Unless required by applicable law or agreed to in writing, software 11b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 12b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * See the License for the specific language governing permissions and 14b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * limitations under the License 15b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey */ 16b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 1728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarpackage com.android.providers.contacts; 18b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 19619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.ContentValues; 20b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.content.Context; 2135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport com.android.internal.content.SyncStateContentProviderHelper; 22619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.pm.ApplicationInfo; 23619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.pm.PackageManager; 24619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.pm.PackageManager.NameNotFoundException; 25619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.database.Cursor; 26b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.database.DatabaseUtils; 27b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.database.sqlite.SQLiteDatabase; 28b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.database.sqlite.SQLiteDoneException; 29b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikovimport android.database.sqlite.SQLiteException; 30b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.database.sqlite.SQLiteOpenHelper; 31bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikovimport android.database.sqlite.SQLiteQueryBuilder; 32b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.database.sqlite.SQLiteStatement; 33619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.os.Binder; 34b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.provider.BaseColumns; 35619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.provider.SocialContract.Activities; 36de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Aggregates; 37b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions; 38de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Contacts; 39de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Data; 40ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.Groups; 411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkeyimport android.provider.ContactsContract.Presence; 42619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.provider.ContactsContract.RestrictionExceptions; 431f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Email; 44ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.GroupMembership; 451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Im; 46bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone; 47619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 48bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikovimport android.telephony.PhoneNumberUtils; 49b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.util.Log; 50b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 51b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport java.util.HashMap; 52619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport java.util.LinkedList; 53b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 54b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey/** 55b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * Database open helper for contacts and social activity data. Designed as a 567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana * singleton to make sure that all {@link android.content.ContentProvider} users get the same 57b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * reference. Provides handy methods for maintaining package and mime-type 58b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * lookup tables. 59b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey */ 60b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey/* package */ class OpenHelper extends SQLiteOpenHelper { 61b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey private static final String TAG = "OpenHelper"; 62b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 63035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana private static final int DATABASE_VERSION = 39; 64b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey private static final String DATABASE_NAME = "contacts2.db"; 651f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey private static final String DATABASE_PRESENCE = "presence_db"; 66b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 67b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public interface Tables { 687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana public static final String ACCOUNTS = "accounts"; 69b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String AGGREGATES = "aggregates"; 70b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String CONTACTS = "contacts"; 71ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String PACKAGES = "packages"; 72ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String MIMETYPES = "mimetypes"; 73b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String PHONE_LOOKUP = "phone_lookup"; 74a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public static final String NAME_LOOKUP = "name_lookup"; 75b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov public static final String AGGREGATION_EXCEPTIONS = "agg_exceptions"; 76619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public static final String RESTRICTION_EXCEPTIONS = "rest_exceptions"; 77d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov public static final String CONTACT_OPTIONS = "contact_options"; 78b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String DATA = "data"; 79ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String GROUPS = "groups"; 801f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey public static final String PRESENCE = "presence"; 81b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public static final String NICKNAME_LOOKUP = "nickname_lookup"; 82b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 831f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey public static final String AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE = "aggregates " 84fb241add950ad1314dff339805cb9eb2d6136f96Jeff Sharkey + "LEFT OUTER JOIN presence ON (aggregates._id = presence.aggregate_id) " 85619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + "LEFT OUTER JOIN data ON (primary_phone_id = data._id)"; 8600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 87ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String DATA_JOIN_MIMETYPES = "data " 88ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id)"; 89b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 90bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov public static final String DATA_JOIN_MIMETYPE_CONTACTS = "data " 9128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id) " 92bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id)"; 93bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov 94ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String DATA_JOIN_CONTACTS_GROUPS = "data " 95ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id)" 96ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN groups ON (groups._id = data." + GroupMembership.GROUP_ROW_ID 97ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + ")"; 98ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 99ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES = "data " 100ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id) " 101619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id) " 102ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN packages ON (contacts.package_id = packages._id)"; 1037e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 104ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES = "data " 105ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id) " 106ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id) " 107ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN packages ON (contacts.package_id = packages._id) " 108ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN aggregates ON (contacts.aggregate_id = aggregates._id)"; 109ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 110ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String DATA_JOIN_MIMETYPES_CONTACTS_PACKAGES_GROUPS = "data " 111ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id) " 112ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id) " 113ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN packages ON (contacts.package_id = packages._id) " 114ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN groups ON (groups._id = data." + GroupMembership.GROUP_ROW_ID 115ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + ")"; 116ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 117ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String GROUPS_JOIN_PACKAGES = "groups " 118ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN packages ON (groups.package_id = packages._id)"; 119ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 120ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES = "data " 121ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id) " 122619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id) " 123ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN aggregates ON (contacts.aggregate_id = aggregates._id)"; 124ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 125ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String GROUPS_JOIN_PACKAGES_DATA_CONTACTS_AGGREGATES = "groups " 126ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN packages ON (groups.package_id = packages._id) " 127ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN data ON (groups._id = data." + GroupMembership.GROUP_ROW_ID 128ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + ") " + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id) " 129619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + "LEFT OUTER JOIN aggregates ON (contacts.aggregate_id = aggregates._id)"; 130b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 131b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String ACTIVITIES = "activities"; 132b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 133ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String ACTIVITIES_JOIN_MIMETYPES = "activities " 134ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN mimetypes ON (activities.mimetype_id = mimetypes._id)"; 135b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 136ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String ACTIVITIES_JOIN_MIMETYPES_CONTACTS_PACKAGES_AGGREGATES = "activities " 137ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN mimetypes ON (activities.mimetype_id = mimetypes._id) " 138619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + "LEFT OUTER JOIN contacts ON (activities.author_contact_id = contacts._id) " 139ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "LEFT OUTER JOIN packages ON (contacts.package_id = packages._id) " 140619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + "LEFT OUTER JOIN aggregates ON (contacts.aggregate_id = aggregates._id)"; 1417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 142035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana public static final String CONTACTS_JOIN_PACKAGES = "contacts " 143035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana + "LEFT OUTER JOIN packages ON (contacts.package_id = packages._id) "; 144b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 145a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public static final String NAME_LOOKUP_JOIN_CONTACTS = "name_lookup " 146a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov + "INNER JOIN contacts ON (name_lookup.contact_id = contacts._id)"; 147b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 148127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov public static final String AGGREGATION_EXCEPTIONS_JOIN_CONTACTS = "agg_exceptions " 149b86b7796abc1a980d7e87afd6c1f05fe0fabe4fdDmitri Plotnikov + "INNER JOIN contacts contacts1 " 150127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov + "ON (agg_exceptions.contact_id1 = contacts1._id) "; 151127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 152b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov public static final String AGGREGATION_EXCEPTIONS_JOIN_CONTACTS_TWICE = "agg_exceptions " 153d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov + "INNER JOIN contacts contacts1 " 154d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov + "ON (agg_exceptions.contact_id1 = contacts1._id) " 155d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov + "INNER JOIN contacts contacts2 " 156d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov + "ON (agg_exceptions.contact_id2 = contacts2._id) "; 157d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 158d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov public static final String CONTACTS_JOIN_CONTACT_OPTIONS = "contacts " 159d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov + "LEFT OUTER JOIN contact_options ON (contacts._id = contact_options._id)"; 160b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 161b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 1621f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey public interface Clauses { 163ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String WHERE_IM_MATCHES = MimetypesColumns.MIMETYPE + "=" + Im.MIMETYPE 1641f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey + " AND " + Im.PROTOCOL + "=? AND " + Im.DATA + "=?"; 1651f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 166ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String WHERE_EMAIL_MATCHES = MimetypesColumns.MIMETYPE + "=" 1671f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey + Email.MIMETYPE + " AND " + Email.DATA + "=?"; 168ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 169ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String MIMETYPE_IS_GROUP_MEMBERSHIP = MimetypesColumns.CONCRETE_MIMETYPE 170ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "='" + GroupMembership.CONTENT_ITEM_TYPE + "'"; 171ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 172ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String BELONGS_TO_GROUP = DataColumns.CONCRETE_GROUP_ID + "=" 173ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + GroupsColumns.CONCRETE_ID; 174ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 175ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String HAS_PRIMARY_PHONE = "(" 176ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID + " IS NOT NULL OR " 177ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID + " IS NOT NULL)"; 178ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 179ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // TODO: add in check against package_visible 180ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String IN_VISIBLE_GROUP = "SELECT MIN(COUNT(" + DataColumns.CONCRETE_ID 181ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + "),1) FROM " + Tables.DATA_JOIN_CONTACTS_GROUPS + " WHERE " 182ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + DataColumns.MIMETYPE_ID + "=? AND " + Contacts.AGGREGATE_ID + "=" 183ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + AggregatesColumns.CONCRETE_ID + " AND " + Groups.GROUP_VISIBLE + "=1"; 1841f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 1851f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 186619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public interface AggregatesColumns { 187619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public static final String OPTIMAL_PRIMARY_PHONE_ID = "optimal_phone_id"; 188619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public static final String OPTIMAL_PRIMARY_PHONE_PACKAGE_ID = "optimal_phone_package_id"; 189619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public static final String FALLBACK_PRIMARY_PHONE_ID = "fallback_phone_id"; 190619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 191619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public static final String OPTIMAL_PRIMARY_EMAIL_ID = "optimal_email_id"; 192619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public static final String OPTIMAL_PRIMARY_EMAIL_PACKAGE_ID = "optimal_email_package_id"; 193619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public static final String FALLBACK_PRIMARY_EMAIL_ID = "fallback_email_id"; 194619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 195619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public static final String SINGLE_RESTRICTED_PACKAGE_ID = "single_restricted_package_id"; 196ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 197ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String CONCRETE_ID = Tables.AGGREGATES + "." + BaseColumns._ID; 198619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 199619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 200619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public interface ContactsColumns { 201b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String PACKAGE_ID = "package_id"; 202ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 203ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String CONCRETE_ID = Tables.CONTACTS + "." + BaseColumns._ID; 204619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 205619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 206619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public interface DataColumns { 207b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String MIMETYPE_ID = "mimetype_id"; 208ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 209ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String CONCRETE_ID = Tables.DATA + "." + BaseColumns._ID; 210ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String CONCRETE_CONTACT_ID = Tables.DATA + "." + Data.CONTACT_ID; 211ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String CONCRETE_GROUP_ID = Tables.DATA + "." 212ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + GroupMembership.GROUP_ROW_ID; 213ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 214ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 215ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public interface GroupsColumns { 216ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String CONCRETE_ID = Tables.GROUPS + "." + BaseColumns._ID; 217ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String CONCRETE_PACKAGE_ID = Tables.GROUPS + "." + Groups.PACKAGE_ID; 218b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 219b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 220b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public interface ActivitiesColumns { 221b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String PACKAGE_ID = "package_id"; 222b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String MIMETYPE_ID = "mimetype_id"; 223b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 224b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 225b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public interface PhoneLookupColumns { 226b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String _ID = BaseColumns._ID; 227b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String DATA_ID = "data_id"; 228b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String CONTACT_ID = "contact_id"; 229b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String NORMALIZED_NUMBER = "normalized_number"; 230b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 231b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 232a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public interface NameLookupColumns { 233a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public static final String _ID = BaseColumns._ID; 234a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public static final String CONTACT_ID = "contact_id"; 235a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public static final String NORMALIZED_NAME = "normalized_name"; 236a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public static final String NAME_TYPE = "name_type"; 237a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 238a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 239a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov public final static class NameLookupType { 240a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public static final int FULL_NAME = 0; 241a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public static final int FULL_NAME_CONCATENATED = 1; 242a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public static final int FULL_NAME_REVERSE = 2; 243a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public static final int FULL_NAME_REVERSE_CONCATENATED = 3; 244b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public static final int FULL_NAME_WITH_NICKNAME = 4; 245b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public static final int FULL_NAME_WITH_NICKNAME_REVERSE = 5; 246b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public static final int GIVEN_NAME_ONLY = 6; 247b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public static final int GIVEN_NAME_ONLY_AS_NICKNAME = 7; 248b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public static final int FAMILY_NAME_ONLY = 8; 249b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public static final int FAMILY_NAME_ONLY_AS_NICKNAME = 9; 250b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public static final int NICKNAME = 10; 251a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov public static final int EMAIL_BASED_NICKNAME = 11; 252a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 253a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov // This is the highest name lookup type code plus one 254a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov public static final int TYPE_COUNT = 12; 255a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov 256a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov public static boolean isBasedOnStructuredName(int nameLookupType) { 257a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov return nameLookupType != NameLookupType.EMAIL_BASED_NICKNAME 258a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov && nameLookupType != NameLookupType.NICKNAME; 259a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov } 260a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 261a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 262ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public interface PackagesColumns { 263b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String _ID = BaseColumns._ID; 264b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String PACKAGE = "package"; 265b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 266b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 267ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public interface MimetypesColumns { 268b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String _ID = BaseColumns._ID; 269b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static final String MIMETYPE = "mimetype"; 270ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 271ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String CONCRETE_ID = Tables.MIMETYPES + "." + BaseColumns._ID; 272ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public static final String CONCRETE_MIMETYPE = Tables.MIMETYPES + "." + MIMETYPE; 273b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 274b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 275b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov public interface AggregationExceptionColumns { 276b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov public static final String _ID = BaseColumns._ID; 277127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov public static final String CONTACT_ID1 = "contact_id1"; 278127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov public static final String CONTACT_ID2 = "contact_id2"; 279b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 280b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 281619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public interface RestrictionExceptionsColumns { 282619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public static final String PACKAGE_PROVIDER_ID = "package_provider_id"; 283619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public static final String PACKAGE_CLIENT_ID = "package_client_id"; 284619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 285619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 286d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov public interface ContactOptionsColumns { 287d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov public static final String _ID = BaseColumns._ID; 288d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov public static final String CUSTOM_RINGTONE = "custom_ringtone"; 289d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov public static final String SEND_TO_VOICEMAIL = "send_to_voicemail"; 290d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 291d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 292b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public interface NicknameLookupColumns { 293b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public static final String NAME = "name"; 294b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public static final String CLUSTER = "cluster"; 295b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 296b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 297b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov private static final String[] NICKNAME_LOOKUP_COLUMNS = new String[] { 298b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov NicknameLookupColumns.CLUSTER 299b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov }; 300b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 301b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov private static final int COL_NICKNAME_LOOKUP_CLUSTER = 0; 302b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 303b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey /** In-memory cache of previously found mimetype mappings */ 304bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov private final HashMap<String, Long> mMimetypeCache = new HashMap<String, Long>(); 305b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey /** In-memory cache of previously found package name mappings */ 306bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov private final HashMap<String, Long> mPackageCache = new HashMap<String, Long>(); 307b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 308b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 309b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey /** Compiled statements for querying and inserting mappings */ 310b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey private SQLiteStatement mMimetypeQuery; 311b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey private SQLiteStatement mPackageQuery; 3126bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov private SQLiteStatement mAggregateIdQuery; 31361bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov private SQLiteStatement mAggregateIdUpdate; 314b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey private SQLiteStatement mMimetypeInsert; 315b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey private SQLiteStatement mPackageInsert; 31661bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov private SQLiteStatement mNameLookupInsert; 317b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 318b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey private SQLiteStatement mDataMimetypeQuery; 319b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey private SQLiteStatement mActivitiesMimetypeQuery; 320b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 321b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov private final Context mContext; 32235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private final SyncStateContentProviderHelper mSyncState; 323619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private final RestrictionExceptionsCache mCache; 324b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov private HashMap<String, String[]> mNicknameClusterCache; 325b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 326ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Compiled statements for updating {@link Aggregates#IN_VISIBLE_GROUP}. */ 327ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private SQLiteStatement mVisibleAllUpdate; 328ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private SQLiteStatement mVisibleSpecificUpdate; 329ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 330619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 331b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey private static OpenHelper sSingleton = null; 332b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 333b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public static synchronized OpenHelper getInstance(Context context) { 334b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey if (sSingleton == null) { 335b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey sSingleton = new OpenHelper(context); 336b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 337b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return sSingleton; 338b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 339b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 3401f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey /** 34131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov * Private constructor, callers except unit tests should obtain an instance through 34235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana * {@link #getInstance(android.content.Context)} instead. 3431f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 34431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /* package */ OpenHelper(Context context) { 345b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey super(context, DATABASE_NAME, null, DATABASE_VERSION); 346b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Log.i(TAG, "Creating OpenHelper"); 347619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 348b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov mContext = context; 349619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey mCache = new RestrictionExceptionsCache(); 350619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey mCache.loadFromDatabase(context, getReadableDatabase()); 35135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana mSyncState = new SyncStateContentProviderHelper(); 35235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 353b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 354b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 355b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey @Override 356b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public void onOpen(SQLiteDatabase db) { 35735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana mSyncState.onDatabaseOpened(db); 35835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 359b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Create compiled statements for package and mimetype lookups 360ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mMimetypeQuery = db.compileStatement("SELECT " + MimetypesColumns._ID + " FROM " 361ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Tables.MIMETYPES + " WHERE " + MimetypesColumns.MIMETYPE + "=?"); 362ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mPackageQuery = db.compileStatement("SELECT " + PackagesColumns._ID + " FROM " 363ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Tables.PACKAGES + " WHERE " + PackagesColumns.PACKAGE + "=?"); 3646bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov mAggregateIdQuery = db.compileStatement("SELECT " + Contacts.AGGREGATE_ID + " FROM " 3656bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov + Tables.CONTACTS + " WHERE " + Contacts._ID + "=?"); 36661bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov mAggregateIdUpdate = db.compileStatement("UPDATE " + Tables.CONTACTS + " SET " 36761bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov + Contacts.AGGREGATE_ID + "=?" + " WHERE " + Contacts._ID + "=?"); 368ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mMimetypeInsert = db.compileStatement("INSERT INTO " + Tables.MIMETYPES + "(" 369ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + MimetypesColumns.MIMETYPE + ") VALUES (?)"); 370ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mPackageInsert = db.compileStatement("INSERT INTO " + Tables.PACKAGES + "(" 371ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + PackagesColumns.PACKAGE + ") VALUES (?)"); 372ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 373ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mDataMimetypeQuery = db.compileStatement("SELECT " + MimetypesColumns.MIMETYPE + " FROM " 374ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Tables.DATA_JOIN_MIMETYPES + " WHERE " + Tables.DATA + "." + Data._ID + "=?"); 375ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mActivitiesMimetypeQuery = db.compileStatement("SELECT " + MimetypesColumns.MIMETYPE 376ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + " FROM " + Tables.ACTIVITIES_JOIN_MIMETYPES + " WHERE " + Tables.ACTIVITIES + "." 377b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey + Activities._ID + "=?"); 37861bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov mNameLookupInsert = db.compileStatement("INSERT INTO " + Tables.NAME_LOOKUP + "(" 37961bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov + NameLookupColumns.CONTACT_ID + "," + NameLookupColumns.NAME_TYPE + "," 38061bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov + NameLookupColumns.NORMALIZED_NAME + ") VALUES (?,?,?)"); 3811f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 382ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final String visibleUpdate = "UPDATE " + Tables.AGGREGATES + " SET " 383ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + Aggregates.IN_VISIBLE_GROUP + "= (" + Clauses.IN_VISIBLE_GROUP + ")"; 384ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 385ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mVisibleAllUpdate = db.compileStatement(visibleUpdate); 386ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mVisibleSpecificUpdate = db.compileStatement(visibleUpdate + " WHERE " 387ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey + AggregatesColumns.CONCRETE_ID + "=?"); 388ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3891f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // Make sure we have an in-memory presence table 3901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final String tableName = DATABASE_PRESENCE + "." + Tables.PRESENCE; 3911f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey final String indexName = DATABASE_PRESENCE + ".presenceIndex"; 3921f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3931f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey db.execSQL("ATTACH DATABASE ':memory:' AS " + DATABASE_PRESENCE + ";"); 3941f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey db.execSQL("CREATE TABLE IF NOT EXISTS " + tableName + " ("+ 3951f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey BaseColumns._ID + " INTEGER PRIMARY KEY," + 3961f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Presence.AGGREGATE_ID + " INTEGER REFERENCES aggregates(_id)," + 3971f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Presence.DATA_ID + " INTEGER REFERENCES data(_id)," + 3981f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Presence.IM_PROTOCOL + " TEXT," + 3991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Presence.IM_HANDLE + " TEXT," + 4001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Presence.IM_ACCOUNT + " TEXT," + 4011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Presence.PRESENCE_STATUS + " INTEGER," + 4021f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Presence.PRESENCE_CUSTOM_STATUS + " TEXT," + 4031f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey "UNIQUE(" + Presence.IM_PROTOCOL + ", " + Presence.IM_HANDLE + ", " + Presence.IM_ACCOUNT + ")" + 4041f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey ");"); 4051f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 406fb241add950ad1314dff339805cb9eb2d6136f96Jeff Sharkey db.execSQL("CREATE INDEX IF NOT EXISTS " + indexName + " ON " + Tables.PRESENCE + " (" 4071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey + Presence.AGGREGATE_ID + ");"); 408b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 409b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 410b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey @Override 411b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public void onCreate(SQLiteDatabase db) { 412b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Log.i(TAG, "Bootstrapping database"); 413b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 41435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana mSyncState.createDatabase(db); 41535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 416b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // One row per group of contacts corresponding to the same person 417b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.execSQL("CREATE TABLE " + Tables.AGGREGATES + " (" + 418b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 419b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Aggregates.DISPLAY_NAME + " TEXT," + 420b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Aggregates.TIMES_CONTACTED + " INTEGER," + 421b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Aggregates.LAST_TIME_CONTACTED + " INTEGER," + 42200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar Aggregates.STARRED + " INTEGER," + 423619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID + " INTEGER REFERENCES data(_id)," + 424619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_PHONE_PACKAGE_ID + " INTEGER REFERENCES package(_id)," + 425619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID + " INTEGER REFERENCES data(_id)," + 426619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID + " INTEGER REFERENCES data(_id)," + 427619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_PACKAGE_ID + " INTEGER REFERENCES package(_id)," + 428619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID + " INTEGER REFERENCES data(_id)," + 429619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey AggregatesColumns.SINGLE_RESTRICTED_PACKAGE_ID + " INTEGER REFERENCES package(_id)," + 430de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millar Aggregates.PHOTO_ID + " INTEGER REFERENCES data(_id)," + 431d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov Aggregates.CUSTOM_RINGTONE + " TEXT," + 43228f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar Aggregates.SEND_TO_VOICEMAIL + " INTEGER NOT NULL DEFAULT 0," + 43328f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar Aggregates.IN_VISIBLE_GROUP + " INTEGER NOT NULL DEFAULT 1" + 434b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey ");"); 435b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 436b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Contacts table 437b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.execSQL("CREATE TABLE " + Tables.CONTACTS + " (" + 438b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Contacts._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 439619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey ContactsColumns.PACKAGE_ID + " INTEGER REFERENCES package(_id) NOT NULL," + 440619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey Contacts.IS_RESTRICTED + " INTEGER NOT NULL DEFAULT 0," + 441035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.ACCOUNT_NAME + " STRING DEFAULT NULL, " + 442035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Contacts.ACCOUNT_TYPE + " STRING DEFAULT NULL, " + 4437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana Contacts.SOURCE_ID + " TEXT," + 4447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana Contacts.VERSION + " INTEGER NOT NULL DEFAULT 1," + 4457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana Contacts.DIRTY + " INTEGER NOT NULL DEFAULT 1," + 446a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov Contacts.AGGREGATE_ID + " INTEGER " + 447b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey ");"); 448b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 449d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Contact options table. It has the same primary key as the corresponding contact. 450d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov db.execSQL("CREATE TABLE " + Tables.CONTACT_OPTIONS + " (" + 451d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov ContactOptionsColumns._ID + " INTEGER PRIMARY KEY," + 452d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov ContactOptionsColumns.CUSTOM_RINGTONE + " TEXT," + 453d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov ContactOptionsColumns.SEND_TO_VOICEMAIL + " INTEGER NOT NULL DEFAULT 0" + 454d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov ");"); 455d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 456b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Package name mapping table 457ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey db.execSQL("CREATE TABLE " + Tables.PACKAGES + " (" + 458ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey PackagesColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 459ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey PackagesColumns.PACKAGE + " TEXT NOT NULL" + 460b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey ");"); 461b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 462ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Mimetype mapping table 463ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey db.execSQL("CREATE TABLE " + Tables.MIMETYPES + " (" + 464ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey MimetypesColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 465ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey MimetypesColumns.MIMETYPE + " TEXT NOT NULL" + 466b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey ");"); 467b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 468b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Public generic data table 469b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.execSQL("CREATE TABLE " + Tables.DATA + " (" + 470b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Data._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 471b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey DataColumns.MIMETYPE_ID + " INTEGER REFERENCES mimetype(_id) NOT NULL," + 472b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Data.CONTACT_ID + " INTEGER NOT NULL," + 473f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.IS_PRIMARY + " INTEGER NOT NULL DEFAULT 0," + 474f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.IS_SUPER_PRIMARY + " INTEGER NOT NULL DEFAULT 0," + 475f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.DATA_VERSION + " INTEGER NOT NULL DEFAULT 0," + 476f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.DATA1 + " TEXT," + 477f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.DATA2 + " TEXT," + 478f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.DATA3 + " TEXT," + 479f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.DATA4 + " TEXT," + 480f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.DATA5 + " TEXT," + 481f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.DATA6 + " TEXT," + 482f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.DATA7 + " TEXT," + 483f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.DATA8 + " TEXT," + 484f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.DATA9 + " TEXT," + 485f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana Data.DATA10 + " TEXT" + 486b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey ");"); 487b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 488f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana /** 489f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana * set contact.dirty whenever the contact is updated and the new version does not explicity 490f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana * clear the dirty flag 491f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana * 492f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana * Want to have a data row that has the server version of the contact. Then when I save 493f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana * an entry from the server into the provider I will set the server version of the data 494f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana * while also clearing the dirty flag of the contact. 495f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana * 496f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana * increment the contact.version whenever the contact is updated 497f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana */ 498f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana db.execSQL("CREATE TRIGGER " + Tables.CONTACTS + "_updated1 " 499f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " BEFORE UPDATE ON " + Tables.CONTACTS 500f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " BEGIN " 501f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " UPDATE " + Tables.CONTACTS 502f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " SET " 503f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + Contacts.VERSION + "=OLD." + Contacts.VERSION + "+1, " 504f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + Contacts.DIRTY + "=1" 505f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " WHERE " + Contacts._ID + "=OLD." + Contacts._ID + ";" 506f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " END"); 507f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana 508f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana db.execSQL("CREATE TRIGGER " + Tables.CONTACTS + "_deleted " 509f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " BEFORE DELETE ON " + Tables.CONTACTS 510f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " BEGIN " 511f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " DELETE FROM " + Tables.DATA 512f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " WHERE " + Data.CONTACT_ID + "=OLD." + Contacts._ID + ";" 513f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " DELETE FROM " + Tables.PHONE_LOOKUP 514f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " WHERE " + PhoneLookupColumns.CONTACT_ID + "=OLD." + Contacts._ID + ";" 515f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " END"); 516f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana 517f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana db.execSQL("CREATE TRIGGER " + Tables.DATA + "_updated AFTER UPDATE ON " + Tables.DATA 518f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " BEGIN " 519f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " UPDATE " + Tables.DATA 520f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " SET " + Data.DATA_VERSION + "=OLD." + Data.DATA_VERSION + "+1 " 521f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " WHERE " + Data._ID + "=OLD." + Data._ID + ";" 522f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " UPDATE " + Tables.CONTACTS 523f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " SET " + Contacts.DIRTY + "=1" 524f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " WHERE " + Contacts._ID + "=OLD." + Contacts._ID + ";" 525f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " END"); 526f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana 527f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana db.execSQL("CREATE TRIGGER " + Tables.DATA + "_deleted BEFORE DELETE ON " + Tables.DATA 528f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " BEGIN " 529f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " UPDATE " + Tables.CONTACTS 530f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " SET " + Contacts.DIRTY + "=1" 531f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " WHERE " + Contacts._ID + "=OLD." + Contacts._ID + ";" 532f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " DELETE FROM " + Tables.PHONE_LOOKUP 533f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " WHERE " + PhoneLookupColumns.DATA_ID + "=OLD." + Data._ID + ";" 534f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana + " END"); 535f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana 536b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Private phone numbers table used for lookup 537b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.execSQL("CREATE TABLE " + Tables.PHONE_LOOKUP + " (" + 538b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey PhoneLookupColumns._ID + " INTEGER PRIMARY KEY," + 539b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey PhoneLookupColumns.DATA_ID + " INTEGER REFERENCES data(_id) NOT NULL," + 540b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey PhoneLookupColumns.CONTACT_ID + " INTEGER REFERENCES contacts(_id) NOT NULL," + 541b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey PhoneLookupColumns.NORMALIZED_NUMBER + " TEXT NOT NULL" + 542b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey ");"); 543b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 544b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.execSQL("CREATE INDEX phone_lookup_index ON " + Tables.PHONE_LOOKUP + " (" + 545b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey PhoneLookupColumns.NORMALIZED_NUMBER + " ASC, " + 546b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey PhoneLookupColumns.CONTACT_ID + ", " + 547b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey PhoneLookupColumns.DATA_ID + 548b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey ");"); 549b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 550a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov // Private name/nickname table used for lookup 551a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov db.execSQL("CREATE TABLE " + Tables.NAME_LOOKUP + " (" + 552a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov NameLookupColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 553a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov NameLookupColumns.CONTACT_ID + " INTEGER REFERENCES contacts(_id) NOT NULL," + 554619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey NameLookupColumns.NORMALIZED_NAME + " TEXT," + 555a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov NameLookupColumns.NAME_TYPE + " INTEGER" + 556a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov ");"); 557a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 558a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov db.execSQL("CREATE INDEX name_lookup_index ON " + Tables.NAME_LOOKUP + " (" + 559a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov NameLookupColumns.NORMALIZED_NAME + " ASC, " + 560a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov NameLookupColumns.NAME_TYPE + " ASC, " + 56161bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov NameLookupColumns.CONTACT_ID + 562a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov ");"); 563a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 564b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov db.execSQL("CREATE TABLE " + Tables.NICKNAME_LOOKUP + " (" + 565b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov NicknameLookupColumns.NAME + " TEXT," + 566b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov NicknameLookupColumns.CLUSTER + " TEXT" + 567b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov ");"); 568b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 569b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov db.execSQL("CREATE UNIQUE INDEX nickname_lookup_index ON " + Tables.NICKNAME_LOOKUP + " (" + 570b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov NicknameLookupColumns.NAME + ", " + 571b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov NicknameLookupColumns.CLUSTER + 572b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov ");"); 573b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 574ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Groups table 575ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey db.execSQL("CREATE TABLE " + Tables.GROUPS + " (" + 576ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Groups._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 577ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Groups.PACKAGE_ID + " INTEGER REFERENCES package(_id) NOT NULL," + 578035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Groups.ACCOUNT_NAME + " STRING DEFAULT NULL, " + 579035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana Groups.ACCOUNT_TYPE + " STRING DEFAULT NULL, " + 580ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Groups.SOURCE_ID + " TEXT," + 581ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Groups.TITLE + " TEXT," + 582ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Groups.TITLE_RESOURCE + " INTEGER," + 583ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey Groups.GROUP_VISIBLE + " INTEGER" + 584ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey ");"); 585ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 586b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov db.execSQL("CREATE TABLE IF NOT EXISTS " + Tables.AGGREGATION_EXCEPTIONS + " (" + 587b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AggregationExceptionColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 588b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AggregationExceptions.TYPE + " INTEGER NOT NULL, " + 589127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov AggregationExceptionColumns.CONTACT_ID1 + " INTEGER REFERENCES contacts(_id), " + 590127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov AggregationExceptionColumns.CONTACT_ID2 + " INTEGER REFERENCES contacts(_id)" + 591b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov ");"); 592b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 593b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS aggregation_exception_index1 ON " + 594b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov Tables.AGGREGATION_EXCEPTIONS + " (" + 595127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov AggregationExceptionColumns.CONTACT_ID1 + ", " + 596127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov AggregationExceptionColumns.CONTACT_ID2 + 597b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov ");"); 598b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 599b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS aggregation_exception_index2 ON " + 600b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov Tables.AGGREGATION_EXCEPTIONS + " (" + 601127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov AggregationExceptionColumns.CONTACT_ID2 + ", " + 602127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov AggregationExceptionColumns.CONTACT_ID1 + 603b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov ");"); 604b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 605619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Restriction exceptions table 606619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey db.execSQL("CREATE TABLE " + Tables.RESTRICTION_EXCEPTIONS + " (" + 607619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 608619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey RestrictionExceptions.PACKAGE_PROVIDER + " TEXT NOT NULL, " + 609619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey RestrictionExceptions.PACKAGE_CLIENT + " TEXT NOT NULL, " + 610619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey RestrictionExceptionsColumns.PACKAGE_PROVIDER_ID + " INTEGER NOT NULL, " + 611619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey RestrictionExceptionsColumns.PACKAGE_CLIENT_ID + " INTEGER NOT NULL" + 612619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey ");"); 613619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 614b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Activities table 615b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.execSQL("CREATE TABLE " + Tables.ACTIVITIES + " (" + 616b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Activities._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 617b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey ActivitiesColumns.PACKAGE_ID + " INTEGER REFERENCES package(_id) NOT NULL," + 618b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey ActivitiesColumns.MIMETYPE_ID + " INTEGER REFERENCES mimetype(_id) NOT NULL," + 619b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Activities.RAW_ID + " TEXT," + 620499791a4f9ab29fa94ff48dd7acff55b2ac089a7Dmitri Plotnikov Activities.IN_REPLY_TO + " TEXT," + 621b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Activities.AUTHOR_CONTACT_ID + " INTEGER REFERENCES contacts(_id)," + 622b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Activities.TARGET_CONTACT_ID + " INTEGER REFERENCES contacts(_id)," + 623b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Activities.PUBLISHED + " INTEGER NOT NULL," + 624499791a4f9ab29fa94ff48dd7acff55b2ac089a7Dmitri Plotnikov Activities.THREAD_PUBLISHED + " INTEGER NOT NULL," + 625b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Activities.TITLE + " TEXT NOT NULL," + 626b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Activities.SUMMARY + " TEXT," + 627adb55c2d8295d300961d86a3605c8ddc469cd4a2Dmitri Plotnikov Activities.LINK + " TEXT, " + 628b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey Activities.THUMBNAIL + " BLOB" + 629b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey ");"); 630b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 631b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov loadNicknameLookupTable(db); 632b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 633b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 634b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey @Override 635b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 6367e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana Log.i(TAG, "Upgrading from version " + oldVersion + " to " + newVersion 637b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey + ", data will be lost!"); 638b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 6397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana db.execSQL("DROP TABLE IF EXISTS " + Tables.ACCOUNTS + ";"); 640b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.execSQL("DROP TABLE IF EXISTS " + Tables.AGGREGATES + ";"); 641b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.execSQL("DROP TABLE IF EXISTS " + Tables.CONTACTS + ";"); 642ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey db.execSQL("DROP TABLE IF EXISTS " + Tables.PACKAGES + ";"); 643ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey db.execSQL("DROP TABLE IF EXISTS " + Tables.MIMETYPES + ";"); 644b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.execSQL("DROP TABLE IF EXISTS " + Tables.DATA + ";"); 645b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.execSQL("DROP TABLE IF EXISTS " + Tables.PHONE_LOOKUP + ";"); 646a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov db.execSQL("DROP TABLE IF EXISTS " + Tables.NAME_LOOKUP + ";"); 647b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov db.execSQL("DROP TABLE IF EXISTS " + Tables.NICKNAME_LOOKUP + ";"); 648ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey db.execSQL("DROP TABLE IF EXISTS " + Tables.GROUPS + ";"); 649619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey db.execSQL("DROP TABLE IF EXISTS " + Tables.RESTRICTION_EXCEPTIONS + ";"); 650b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey db.execSQL("DROP TABLE IF EXISTS " + Tables.ACTIVITIES + ";"); 651b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 652d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // TODO: we should not be dropping agg_exceptions and contact_options. In case that table's 653d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // schema changes, we should try to preserve the data, because it was entered by the user 654d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // and has never been synched to the server. 655d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov db.execSQL("DROP TABLE IF EXISTS " + Tables.AGGREGATION_EXCEPTIONS + ";"); 656d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov db.execSQL("DROP TABLE IF EXISTS " + Tables.CONTACT_OPTIONS + ";"); 657b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 658b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey onCreate(db); 65935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 66035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana // TODO: eventually when this supports upgrades we should do something like the following: 66135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana// if (!upgradeDatabase(db, oldVersion, newVersion)) { 66235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana// mSyncState.discardSyncData(db, null /* all accounts */); 66335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana// ContentResolver.requestSync(null /* all accounts */, 66435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana// mContentUri.getAuthority(), new Bundle()); 66535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana// } 666b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 667b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 668a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 669a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data except mime type and package lookup tables. 670a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 671a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov public void wipeData() { 672a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov SQLiteDatabase db = getWritableDatabase(); 673a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov db.execSQL("DELETE FROM " + Tables.AGGREGATES + ";"); 674a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov db.execSQL("DELETE FROM " + Tables.CONTACTS + ";"); 675d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov db.execSQL("DELETE FROM " + Tables.CONTACT_OPTIONS + ";"); 676a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov db.execSQL("DELETE FROM " + Tables.DATA + ";"); 677a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov db.execSQL("DELETE FROM " + Tables.PHONE_LOOKUP + ";"); 678a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov db.execSQL("DELETE FROM " + Tables.NAME_LOOKUP + ";"); 679ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey db.execSQL("DELETE FROM " + Tables.GROUPS + ";"); 680b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov db.execSQL("DELETE FROM " + Tables.AGGREGATION_EXCEPTIONS + ";"); 681619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey db.execSQL("DELETE FROM " + Tables.RESTRICTION_EXCEPTIONS + ";"); 682a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov db.execSQL("DELETE FROM " + Tables.ACTIVITIES + ";"); 683b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 684b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov // Note: we are not removing reference data from Tables.NICKNAME_LOOKUP 685b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 686a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov db.execSQL("VACUUM;"); 687a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 688b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 689b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey /** 690619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Return the {@link ApplicationInfo#uid} for the given package name. 691619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 692619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public static int getUidForPackageName(PackageManager pm, String packageName) { 693619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey try { 694619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey ApplicationInfo clientInfo = pm.getApplicationInfo(packageName, 0 /* no flags */); 695619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return clientInfo.uid; 696619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } catch (NameNotFoundException e) { 697619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey throw new RuntimeException(e); 698619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 699619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 700619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 701619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 702b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * Perform an internal string-to-integer lookup using the compiled 703b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * {@link SQLiteStatement} provided, using the in-memory cache to speed up 704b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * lookups. If a mapping isn't found in cache or database, it will be 705b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * created. All new, uncached answers are added to the cache automatically. 706b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * 707b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * @param query Compiled statement used to query for the mapping. 708b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * @param insert Compiled statement used to insert a new mapping when no 709b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * existing one is found in cache or from query. 710b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * @param value Value to find mapping for. 711b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * @param cache In-memory cache of previous answers. 712b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * @return An unique integer mapping for the given value. 713b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey */ 714b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey private synchronized long getCachedId(SQLiteStatement query, SQLiteStatement insert, 715b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey String value, HashMap<String, Long> cache) { 716b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Try an in-memory cache lookup 717b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey if (cache.containsKey(value)) { 718b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return cache.get(value); 719b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 720b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 721b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey long id = -1; 722b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey try { 723b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Try searching database for mapping 724b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey DatabaseUtils.bindObjectToProgram(query, 1, value); 725b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey id = query.simpleQueryForLong(); 726b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } catch (SQLiteDoneException e) { 727b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Nothing found, so try inserting new mapping 728b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey DatabaseUtils.bindObjectToProgram(insert, 1, value); 729b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey id = insert.executeInsert(); 730b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 731b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 732b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey if (id != -1) { 733b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Cache and return the new answer 734b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey cache.put(value, id); 735b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return id; 736b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } else { 737b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Otherwise throw if no mapping found or created 738b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey throw new IllegalStateException("Couldn't find or create internal " 739b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey + "lookup table entry for value " + value); 740b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 741b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 742b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 743b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey /** 744ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Convert a package name into an integer, using {@link Tables#PACKAGES} for 745b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * lookups and possible allocation of new IDs as needed. 746b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey */ 747b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public long getPackageId(String packageName) { 748b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Make sure compiled statements are ready by opening database 749b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey getReadableDatabase(); 750b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return getCachedId(mPackageQuery, mPackageInsert, packageName, mPackageCache); 751b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 752b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 753b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey /** 754ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Convert a mimetype into an integer, using {@link Tables#MIMETYPES} for 755b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * lookups and possible allocation of new IDs as needed. 756b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey */ 757b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public long getMimeTypeId(String mimetype) { 758b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Make sure compiled statements are ready by opening database 759b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey getReadableDatabase(); 760b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return getCachedId(mMimetypeQuery, mMimetypeInsert, mimetype, mMimetypeCache); 761b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 762b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 763b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey /** 764ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Find the mimetype for the given {@link Data#_ID}. 765b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey */ 766b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public String getDataMimeType(long dataId) { 767b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Make sure compiled statements are ready by opening database 768b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey getReadableDatabase(); 769b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey try { 770b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Try database query to find mimetype 771b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey DatabaseUtils.bindObjectToProgram(mDataMimetypeQuery, 1, dataId); 772b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey String mimetype = mDataMimetypeQuery.simpleQueryForString(); 773b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return mimetype; 774b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } catch (SQLiteDoneException e) { 775b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // No valid mapping found, so return null 776b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return null; 777b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 778b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 779b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey 780b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey /** 781b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * Find the mime-type for the given {@link Activities#_ID}. 782b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey */ 783b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey public String getActivityMimeType(long activityId) { 784b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Make sure compiled statements are ready by opening database 785b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey getReadableDatabase(); 786b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey try { 787b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // Try database query to find mimetype 788b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey DatabaseUtils.bindObjectToProgram(mActivitiesMimetypeQuery, 1, activityId); 789b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey String mimetype = mActivitiesMimetypeQuery.simpleQueryForString(); 790b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return mimetype; 791b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } catch (SQLiteDoneException e) { 792b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey // No valid mapping found, so return null 793b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey return null; 794b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 795b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey } 7966bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov 7976bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov /** 798ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Update {@link Aggregates#IN_VISIBLE_GROUP} for all aggregates. 799ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 800ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public void updateAllVisible() { 801ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long groupMembershipMimetypeId = getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 802ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mVisibleAllUpdate.bindLong(1, groupMembershipMimetypeId); 803ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mVisibleAllUpdate.execute(); 804ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 805ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 806ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 807ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Update {@link Aggregates#IN_VISIBLE_GROUP} for a specific aggregate. 808ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 809ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey public void updateAggregateVisible(long aggId) { 810ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey final long groupMembershipMimetypeId = getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 811ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mVisibleSpecificUpdate.bindLong(1, groupMembershipMimetypeId); 812ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mVisibleSpecificUpdate.bindLong(2, aggId); 813ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey mVisibleSpecificUpdate.execute(); 814ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 815ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 816ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 81761bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov * Updates the aggregate ID for the specified contact. 81861bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov */ 81961bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov public void setAggregateId(long contactId, long aggregateId) { 82061bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov getWritableDatabase(); 82161bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov DatabaseUtils.bindObjectToProgram(mAggregateIdUpdate, 1, aggregateId); 82261bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov DatabaseUtils.bindObjectToProgram(mAggregateIdUpdate, 2, contactId); 82361bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov mAggregateIdUpdate.execute(); 82461bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov } 82561bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov 82661bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov /** 8276bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov * Returns aggregate ID for the given contact or zero if it is NULL. 8286bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov */ 8296bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov public long getAggregateId(long contactId) { 8306bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov getReadableDatabase(); 8316bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov try { 8326bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov DatabaseUtils.bindObjectToProgram(mAggregateIdQuery, 1, contactId); 8336bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov return mAggregateIdQuery.simpleQueryForLong(); 8346bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov } catch (SQLiteDoneException e) { 8356bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov // No valid mapping found, so return -1 8366bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov return 0; 8376bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov } 8386bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov } 83961bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov 84061bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov /** 84161bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov * Inserts a record in the {@link Tables#NAME_LOOKUP} table. 84261bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov */ 84361bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov public void insertNameLookup(long contactId, int lookupType, String name) { 84461bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov getWritableDatabase(); 84561bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 1, contactId); 84661bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 2, lookupType); 84761bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 3, name); 84861bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov mNameLookupInsert.executeInsert(); 84961bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov } 850619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 851bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov public static void buildPhoneLookupQuery(SQLiteQueryBuilder qb, final String number) { 852bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov final String normalizedNumber = PhoneNumberUtils.toCallerIDMinMatch(number); 853bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov final StringBuilder tables = new StringBuilder(); 854bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov tables.append("contacts, (SELECT data_id FROM phone_lookup " 855bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov + "WHERE (phone_lookup.normalized_number GLOB '"); 856bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov tables.append(normalizedNumber); 857ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey tables.append("*')) AS lookup, " + Tables.DATA_JOIN_MIMETYPES); 858bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov qb.setTables(tables.toString()); 859bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov qb.appendWhere("lookup.data_id=data._id AND data.contact_id=contacts._id AND "); 860bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov qb.appendWhere("PHONE_NUMBERS_EQUAL(data." + Phone.NUMBER + ", "); 861bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov qb.appendWhereEscapeString(number); 862bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov qb.appendWhere(")"); 863bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov } 864bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov 865bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov 866619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 867b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov * Loads common nickname mappings into the database. 868b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov */ 869b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov private void loadNicknameLookupTable(SQLiteDatabase db) { 87028f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar String[] strings = mContext.getResources().getStringArray( 87128f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar com.android.internal.R.array.common_nicknames); 872b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov if (strings == null || strings.length == 0) { 873b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov return; 874b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 875b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 876b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov SQLiteStatement nicknameLookupInsert = db.compileStatement("INSERT INTO " 877b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov + Tables.NICKNAME_LOOKUP + "(" + NicknameLookupColumns.NAME + "," 878b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov + NicknameLookupColumns.CLUSTER + ") VALUES (?,?)"); 879b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 880b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov for (int clusterId = 0; clusterId < strings.length; clusterId++) { 881b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov String[] names = strings[clusterId].split(","); 882b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov for (int j = 0; j < names.length; j++) { 883b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov String name = NameNormalizer.normalize(names[j]); 884b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov try { 885b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov DatabaseUtils.bindObjectToProgram(nicknameLookupInsert, 1, name); 886b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov DatabaseUtils.bindObjectToProgram(nicknameLookupInsert, 2, 887b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov String.valueOf(clusterId)); 888b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov nicknameLookupInsert.executeInsert(); 889b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } catch (SQLiteException e) { 890b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 891b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov // Print the exception and keep going - this is not a fatal error 892b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov Log.e(TAG, "Cannot insert nickname: " + names[j], e); 893b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 894b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 895b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 896b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 897b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 898b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov /** 899b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov * Returns common nickname cluster IDs for a given name. For example, it 900b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov * will return the same value for "Robert", "Bob" and "Rob". Some names belong to multiple 901b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov * clusters, e.g. Leo could be Leonard or Leopold. 902b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov * 903b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov * May return null. 904b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov * 905b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov * @param normalizedName A normalized first name, see {@link NameNormalizer#normalize}. 906b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov */ 907b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov public String[] getCommonNicknameClusters(String normalizedName) { 908b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov if (mNicknameClusterCache == null) { 909b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov mNicknameClusterCache = new HashMap<String, String[]>(); 910b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 911b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 912b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov synchronized (mNicknameClusterCache) { 913b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov if (mNicknameClusterCache.containsKey(normalizedName)) { 914b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov return mNicknameClusterCache.get(normalizedName); 915b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 916b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 917b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 918b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov String[] clusters = null; 919b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov SQLiteDatabase db = getReadableDatabase(); 920b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 921b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov Cursor cursor = db.query(Tables.NICKNAME_LOOKUP, NICKNAME_LOOKUP_COLUMNS, 922b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov NicknameLookupColumns.NAME + "=?", new String[] { normalizedName }, 923b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov null, null, null); 924b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov try { 925b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov int count = cursor.getCount(); 926b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov if (count > 0) { 927b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov clusters = new String[count]; 928b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov for (int i = 0; i < count; i++) { 929b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov cursor.moveToNext(); 930b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov clusters[i] = cursor.getString(COL_NICKNAME_LOOKUP_CLUSTER); 931b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 932b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 933b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } finally { 934b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov cursor.close(); 935b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 936b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 937b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov synchronized (mNicknameClusterCache) { 938b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov mNicknameClusterCache.put(normalizedName, clusters); 939b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 940b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 941b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov return clusters; 942b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov } 943b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov 944b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov /** 945619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Add a {@link RestrictionExceptions} record. This will update the 946619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * in-memory lookup table, and write to the database when needed. Any 947619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * callers should enforce that the {@link Binder#getCallingUid()} has the 948619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * authority to grant exceptions. 949619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 950619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public void addRestrictionException(Context context, ContentValues values) { 951619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final PackageManager pm = context.getPackageManager(); 952619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final SQLiteDatabase db = this.getWritableDatabase(); 953619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 954619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Read incoming package values and find lookup values 955619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String packageProvider = values.getAsString(RestrictionExceptions.PACKAGE_PROVIDER); 956619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String packageClient = values.getAsString(RestrictionExceptions.PACKAGE_CLIENT); 957619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final long packageProviderId = getPackageId(packageProvider); 958619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final long packageClientId = getPackageId(packageClient); 959619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 960619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Find the client UID to update our internal lookup table and write the 961619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // exception to our database if we changed the in-memory cache. 962619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int clientUid = getUidForPackageName(pm, packageClient); 963619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey boolean cacheChanged = mCache.addException(packageProviderId, clientUid); 964619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (cacheChanged) { 965619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(RestrictionExceptionsColumns.PACKAGE_PROVIDER_ID, packageProviderId); 966619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.put(RestrictionExceptionsColumns.PACKAGE_CLIENT_ID, packageClientId); 967619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey values.remove(RestrictionExceptions.ALLOW_ACCESS); 968619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey db.insert(Tables.RESTRICTION_EXCEPTIONS, null, values); 969619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 970619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 971619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 972619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 973619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 974619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Remove a {@link RestrictionExceptions} record. This will update the 975619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * in-memory lookup table, and write to the database when needed. Any 976619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * callers should enforce that the {@link Binder#getCallingUid()} has the 977619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * authority to revoke exceptions. 978619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 979619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public void removeRestrictionException(Context context, ContentValues values) { 980619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final PackageManager pm = context.getPackageManager(); 981619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final SQLiteDatabase db = this.getWritableDatabase(); 982619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 983619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Read incoming package values and find lookup values 984619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String packageProvider = values.getAsString(RestrictionExceptions.PACKAGE_PROVIDER); 985619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String packageClient = values.getAsString(RestrictionExceptions.PACKAGE_CLIENT); 986619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final long packageProviderId = getPackageId(packageProvider); 987619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final long packageClientId = getPackageId(packageClient); 988619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 989619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Find the client UID to update our internal lookup table and remove 990619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // the exception from our database if we changed the in-memory cache. 991619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int clientUid = getUidForPackageName(pm, packageClient); 992619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final boolean cacheChanged = mCache.removeException(packageProviderId, clientUid); 993619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (cacheChanged) { 994619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey db.delete(Tables.RESTRICTION_EXCEPTIONS, 995619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey RestrictionExceptionsColumns.PACKAGE_PROVIDER_ID + "=" + packageProviderId 996619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + " AND " + RestrictionExceptionsColumns.PACKAGE_CLIENT_ID + "=" 997619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey + packageClientId, null); 998619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 999619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1000619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1001619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1002619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1003619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Return the exception clause that should be used when running {@link Data} 1004619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * queries that may be impacted by {@link Contacts#IS_RESTRICTED}. Will 1005619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * return a clause of all of the provider packages that have granted 1006619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * exceptions to the requested client UID. 1007619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1008619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public String getRestrictionExceptionClause(int clientUid, String column) { 1009619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return mCache.getExceptionQueryClause(clientUid, column); 1010619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1011619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1012619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1013619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Utility class to build a selection query clause that matches a specific 1014619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * column against any one of the contained values. You must provide any 1015619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * escaping of the field values yourself. 1016619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1017619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private static class MatchesClause<T> extends LinkedList<T> { 1018bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov private final HashMap<String, String> mCache = new HashMap<String, String>(); 1019619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1020619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private static final String JOIN_OR = " OR "; 1021619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1022619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public synchronized boolean addMatch(T object) { 1023619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey mCache.clear(); 1024619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return super.add(object); 1025619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1026619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1027619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public synchronized void removeMatch(T object) { 1028619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey mCache.clear(); 1029619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey super.remove(object); 1030619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1031619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1032619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1033619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Return the query clause that would match the given column string to 1034619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * any values added through {@link #addMatch(Object)}. 1035619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1036619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public synchronized String getQueryClause(String column, StringBuilder recycle) { 1037619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // We maintain an internal cache for each requested column, and only 1038619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // build the actual value when needed. 1039619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey String queryClause = mCache.get(column); 1040619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int size = this.size(); 1041619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (queryClause == null && size > 0) { 1042619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey recycle.setLength(0); 1043619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey for (int i = 0; i < size; i++) { 1044619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey recycle.append(column); 1045619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey recycle.append("="); 1046619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey recycle.append(this.get(i)); 1047619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey recycle.append(JOIN_OR); 1048619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1049619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1050619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Trim off the last "OR" clause and store cached value. 1051619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int length = recycle.length(); 1052619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey recycle.delete(length - JOIN_OR.length(), length); 1053619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey queryClause = recycle.toString(); 1054619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey mCache.put(column, queryClause); 1055619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1056619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return queryClause; 1057619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1058619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1059619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1060619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1061619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Optimized in-memory cache for storing {@link RestrictionExceptions} that 1062619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * have been read up from database. Helper methods indicate when an 1063619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * exception change require writing to disk, and build query clauses for a 1064619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * specific {@link RestrictionExceptions#PACKAGE_CLIENT}. 1065619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1066619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private static class RestrictionExceptionsCache extends HashMap<Integer, MatchesClause<Long>> { 1067bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov private final StringBuilder mBuilder = new StringBuilder(); 1068619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1069619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private static final String[] PROJ_RESTRICTION_EXCEPTIONS = new String[] { 1070619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey RestrictionExceptionsColumns.PACKAGE_PROVIDER_ID, 1071619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey RestrictionExceptions.PACKAGE_CLIENT, 1072619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey }; 1073619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1074619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private static final int COL_PACKAGE_PROVIDER_ID = 0; 1075619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private static final int COL_PACKAGE_CLIENT = 1; 1076619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1077619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public void loadFromDatabase(Context context, SQLiteDatabase db) { 1078619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final PackageManager pm = context.getPackageManager(); 1079619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1080619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Load all existing exceptions from our database. 1081619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey Cursor cursor = null; 1082619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey try { 1083619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey cursor = db.query(Tables.RESTRICTION_EXCEPTIONS, PROJ_RESTRICTION_EXCEPTIONS, null, 1084619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey null, null, null, null); 1085619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey while (cursor.moveToNext()) { 1086619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Read provider and client package details from database 1087619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final long packageProviderId = cursor.getLong(COL_PACKAGE_PROVIDER_ID); 1088619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final String clientPackage = cursor.getString(COL_PACKAGE_CLIENT); 1089619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1090619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey try { 1091619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey // Create exception entry for this client 1092619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey final int clientUid = getUidForPackageName(pm, clientPackage); 1093619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey addException(packageProviderId, clientUid); 1094619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } catch (RuntimeException e) { 1095619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey Log.w(TAG, "Failed to grant restriction exception to " + clientPackage); 1096619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey continue; 1097619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1098619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1099619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1100619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } finally { 1101619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (cursor != null) { 1102619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey cursor.close(); 1103619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1104619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1105619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1106619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1107619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1108619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Lazily fetch a {@link MatchesClause} instance, creating a new one if 1109619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * both needed and requested. 1110619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1111619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey private MatchesClause<Long> getLazy(int clientUid, boolean create) { 1112619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey MatchesClause<Long> matchesClause = get(clientUid); 1113619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (matchesClause == null && create) { 1114619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey matchesClause = new MatchesClause<Long>(); 1115619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey put(clientUid, matchesClause); 1116619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1117619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return matchesClause; 1118619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1119619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1120619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1121619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Build a query clause that will allow the restriction exceptions 1122619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * granted to a specific {@link Binder#getCallingUid()}. 1123619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1124619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public String getExceptionQueryClause(int clientUid, String column) { 1125619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey MatchesClause<Long> matchesClause = getLazy(clientUid, false); 1126619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (matchesClause != null) { 1127619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return matchesClause.getQueryClause(column, mBuilder); 1128619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } else { 1129ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // When no matching clause found, return 0 to provide a false 1130ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // value for the query string. 1131ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey return "0"; 1132619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1133619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1134619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1135619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1136619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Add a {@link RestrictionExceptions} into the cache. Returns true if 1137619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * this action resulted in the cache being changed. 1138619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1139619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public boolean addException(long packageProviderId, int clientUid) { 1140619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey MatchesClause<Long> matchesClause = getLazy(clientUid, true); 1141619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (matchesClause.contains(packageProviderId)) { 1142619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return false; 1143619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } else { 1144619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey matchesClause.addMatch(packageProviderId); 1145619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return true; 1146619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1147619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1148619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1149619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 1150619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Remove a {@link RestrictionExceptions} from the cache. Returns true if 1151619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * this action resulted in the cache being changed. 1152619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */ 1153619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey public boolean removeException(long packageProviderId, int clientUid) { 1154619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey MatchesClause<Long> matchesClause = getLazy(clientUid, false); 1155619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey if (matchesClause == null || !matchesClause.contains(packageProviderId)) { 1156619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return false; 1157619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } else { 1158619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey matchesClause.removeMatch(packageProviderId); 1159619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey return true; 1160619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1161619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1162619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 1163619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 116435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana public SyncStateContentProviderHelper getSyncState() { 116535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana return mSyncState; 116635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana } 1167b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey} 1168