ContactsDatabaseHelper.java revision 0f8f3b3e4a6ad18c5868d0215cc137845a2ddc74
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
1967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport com.android.internal.content.SyncStateContentProviderHelper;
2067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
21619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.ContentValues;
22b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.content.Context;
23619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.pm.ApplicationInfo;
24619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.pm.PackageManager;
25619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.pm.PackageManager.NameNotFoundException;
26619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.database.Cursor;
27b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.database.DatabaseUtils;
28b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.database.sqlite.SQLiteDatabase;
29b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.database.sqlite.SQLiteDoneException;
30b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikovimport android.database.sqlite.SQLiteException;
31b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.database.sqlite.SQLiteOpenHelper;
32bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikovimport android.database.sqlite.SQLiteQueryBuilder;
33b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.database.sqlite.SQLiteStatement;
34b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.provider.BaseColumns;
35de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Aggregates;
36b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions;
37de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Contacts;
38de4c4d84028c6c6999c6d9277b54b661f207b992Evan Millarimport android.provider.ContactsContract.Data;
39ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.Groups;
401f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkeyimport android.provider.ContactsContract.Presence;
411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Email;
42ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
431f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Im;
44bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone;
4567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.provider.SocialContract.Activities;
46bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikovimport android.telephony.PhoneNumberUtils;
47b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport android.util.Log;
48b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
49b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkeyimport java.util.HashMap;
50b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
51b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey/**
52b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * Database open helper for contacts and social activity data. Designed as a
537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana * singleton to make sure that all {@link android.content.ContentProvider} users get the same
54b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * reference. Provides handy methods for maintaining package and mime-type
55b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey * lookup tables.
56b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey */
57b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey/* package */ class OpenHelper extends SQLiteOpenHelper {
58b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private static final String TAG = "OpenHelper";
59b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
600f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov    private static final int DATABASE_VERSION = 48;
61b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private static final String DATABASE_NAME = "contacts2.db";
621f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    private static final String DATABASE_PRESENCE = "presence_db";
63b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
64b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    public interface Tables {
657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        public static final String ACCOUNTS = "accounts";
66b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String AGGREGATES = "aggregates";
67b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String CONTACTS = "contacts";
68ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String PACKAGES = "packages";
69ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String MIMETYPES = "mimetypes";
70b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String PHONE_LOOKUP = "phone_lookup";
71a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        public static final String NAME_LOOKUP = "name_lookup";
72b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        public static final String AGGREGATION_EXCEPTIONS = "agg_exceptions";
73b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String DATA = "data";
74ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String GROUPS = "groups";
751f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        public static final String PRESENCE = "presence";
76b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public static final String NICKNAME_LOOKUP = "nickname_lookup";
77b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
781f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        public static final String AGGREGATES_JOIN_PRESENCE_PRIMARY_PHONE = "aggregates "
79fb241add950ad1314dff339805cb9eb2d6136f96Jeff Sharkey                + "LEFT OUTER JOIN presence ON (aggregates._id = presence.aggregate_id) "
80619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                + "LEFT OUTER JOIN data ON (primary_phone_id = data._id)";
8100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
82ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String DATA_JOIN_MIMETYPES = "data "
83ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id)";
84b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
85bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov        public static final String DATA_JOIN_MIMETYPE_CONTACTS = "data "
8628f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id) "
87bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov                + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id)";
88bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov
89ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String DATA_JOIN_CONTACTS_GROUPS = "data "
90ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id)"
91ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN groups ON (groups._id = data." + GroupMembership.GROUP_ROW_ID
92ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + ")";
93ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
9467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS = "data "
9567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + "LEFT OUTER JOIN packages ON (data.package_id = packages._id) "
9667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id) "
9767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id)";
9867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
9967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_AGGREGATES = "data "
10067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + "LEFT OUTER JOIN packages ON (data.package_id = packages._id) "
101ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id) "
102619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id) "
10367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + "LEFT OUTER JOIN aggregates ON (contacts.aggregate_id = aggregates._id)";
1047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
10567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String DATA_JOIN_MIMETYPES_CONTACTS_AGGREGATES = "data "
106ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id) "
107ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id) "
108ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN aggregates ON (contacts.aggregate_id = aggregates._id)";
109ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
11067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_AGGREGATES_GROUPS = "data "
11167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + "LEFT OUTER JOIN packages ON (data.package_id = packages._id) "
1129261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id) "
1139261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "LEFT OUTER JOIN groups "
1149261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "  ON (mimetypes.mimetype='" + GroupMembership.CONTENT_ITEM_TYPE + "' "
1159261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "      AND groups._id = data." + GroupMembership.GROUP_ROW_ID + ") "
1169261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id) "
1179261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "LEFT OUTER JOIN aggregates ON (contacts.aggregate_id = aggregates._id)";
1189261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
11967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String DATA_JOIN_PACKAGES_MIMETYPES_CONTACTS_GROUPS = "data "
12067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + "LEFT OUTER JOIN packages ON (data.package_id = packages._id) "
121ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id = mimetypes._id) "
122ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id) "
1239261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "LEFT OUTER JOIN groups "
1249261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "  ON (mimetypes.mimetype='" + GroupMembership.CONTENT_ITEM_TYPE + "' "
1259261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "      AND groups._id = data." + GroupMembership.GROUP_ROW_ID + ") ";
126ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
127ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String GROUPS_JOIN_PACKAGES = "groups "
128ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN packages ON (groups.package_id = packages._id)";
129ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
130ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String GROUPS_JOIN_PACKAGES_DATA_CONTACTS_AGGREGATES = "groups "
131ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN packages ON (groups.package_id = packages._id) "
1329261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "LEFT OUTER JOIN data "
1339261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "  ON (groups._id = data." + GroupMembership.GROUP_ROW_ID + ") "
1349261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "LEFT OUTER JOIN contacts ON (data.contact_id = contacts._id) "
135619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                + "LEFT OUTER JOIN aggregates ON (contacts.aggregate_id = aggregates._id)";
136b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
137b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String ACTIVITIES = "activities";
138b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
139ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String ACTIVITIES_JOIN_MIMETYPES = "activities "
140ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN mimetypes ON (activities.mimetype_id = mimetypes._id)";
141b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
14267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String ACTIVITIES_JOIN_PACKAGES_MIMETYPES_CONTACTS_AGGREGATES = "activities "
14367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + "LEFT OUTER JOIN packages ON (activities.package_id = packages._id) "
144ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + "LEFT OUTER JOIN mimetypes ON (activities.mimetype_id = mimetypes._id) "
145619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                + "LEFT OUTER JOIN contacts ON (activities.author_contact_id = contacts._id) "
146619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                + "LEFT OUTER JOIN aggregates ON (contacts.aggregate_id = aggregates._id)";
1477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
148a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        public static final String NAME_LOOKUP_JOIN_CONTACTS = "name_lookup "
149a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov                + "INNER JOIN contacts ON (name_lookup.contact_id = contacts._id)";
150b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
151127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        public static final String AGGREGATION_EXCEPTIONS_JOIN_CONTACTS = "agg_exceptions "
152b86b7796abc1a980d7e87afd6c1f05fe0fabe4fdDmitri Plotnikov                + "INNER JOIN contacts contacts1 "
153127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                + "ON (agg_exceptions.contact_id1 = contacts1._id) ";
154127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
155b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        public static final String AGGREGATION_EXCEPTIONS_JOIN_CONTACTS_TWICE = "agg_exceptions "
156d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov                + "INNER JOIN contacts contacts1 "
157d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov                + "ON (agg_exceptions.contact_id1 = contacts1._id) "
158d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov                + "INNER JOIN contacts contacts2 "
159d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov                + "ON (agg_exceptions.contact_id2 = contacts2._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";
1849261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
1859261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        public static final String GROUP_HAS_ACCOUNT_AND_SOURCE_ID =
1869261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Groups.SOURCE_ID + "=? AND "
1879261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                        + Groups.ACCOUNT_NAME + "=? AND "
1889261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                        + Groups.ACCOUNT_TYPE + "=?";
1899261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
1901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    }
1911f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
192619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public interface AggregatesColumns {
193619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        public static final String OPTIMAL_PRIMARY_PHONE_ID = "optimal_phone_id";
19467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String OPTIMAL_PRIMARY_PHONE_IS_RESTRICTED = "optimal_phone_is_restricted";
195619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        public static final String FALLBACK_PRIMARY_PHONE_ID = "fallback_phone_id";
196619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
197619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        public static final String OPTIMAL_PRIMARY_EMAIL_ID = "optimal_email_id";
19867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String OPTIMAL_PRIMARY_EMAIL_IS_RESTRICTED = "optimal_email_is_restricted";
199619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        public static final String FALLBACK_PRIMARY_EMAIL_ID = "fallback_email_id";
200619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
20167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String SINGLE_IS_RESTRICTED = "single_is_restricted";
202ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
203ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String CONCRETE_ID = Tables.AGGREGATES + "." + BaseColumns._ID;
20467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String CONCRETE_DISPLAY_NAME = Tables.AGGREGATES + "."
20567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + Aggregates.DISPLAY_NAME;
20667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
20767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String CONCRETE_TIMES_CONTACTED = Tables.AGGREGATES + "."
20867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + Aggregates.TIMES_CONTACTED;
20967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String CONCRETE_LAST_TIME_CONTACTED = Tables.AGGREGATES + "."
21067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + Aggregates.LAST_TIME_CONTACTED;
21167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String CONCRETE_STARRED = Tables.AGGREGATES + "." + Aggregates.STARRED;
21267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String CONCRETE_CUSTOM_RINGTONE = Tables.AGGREGATES + "."
21367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + Aggregates.CUSTOM_RINGTONE;
21467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String CONCRETE_SEND_TO_VOICEMAIL = Tables.AGGREGATES + "."
21567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                + Aggregates.SEND_TO_VOICEMAIL;
216619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
217619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
218619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public interface ContactsColumns {
219ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String CONCRETE_ID = Tables.CONTACTS + "." + BaseColumns._ID;
2209261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        public static final String CONCRETE_ACCOUNT_NAME =
2219261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Tables.CONTACTS + "." + Contacts.ACCOUNT_NAME;
2229261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        public static final String CONCRETE_ACCOUNT_TYPE =
2239261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Tables.CONTACTS + "." + Contacts.ACCOUNT_TYPE;
2249261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        public static final String CONCRETE_SOURCE_ID = Tables.CONTACTS + "." + Contacts.SOURCE_ID;
2259261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        public static final String CONCRETE_VERSION = Tables.CONTACTS + "." + Contacts.VERSION;
2269261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        public static final String CONCRETE_DIRTY = Tables.CONTACTS + "." + Contacts.DIRTY;
2273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final String DISPLAY_NAME = "display_name";
228619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
229619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
230619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public interface DataColumns {
23167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String PACKAGE_ID = "package_id";
232b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String MIMETYPE_ID = "mimetype_id";
233ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
234ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String CONCRETE_ID = Tables.DATA + "." + BaseColumns._ID;
235ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String CONCRETE_CONTACT_ID = Tables.DATA + "." + Data.CONTACT_ID;
236ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String CONCRETE_GROUP_ID = Tables.DATA + "."
237ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + GroupMembership.GROUP_ROW_ID;
238e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
239e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_DATA1 = Tables.DATA + "." + Data.DATA1;
240e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_DATA2 = Tables.DATA + "." + Data.DATA2;
241e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_DATA3 = Tables.DATA + "." + Data.DATA3;
242e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_DATA4 = Tables.DATA + "." + Data.DATA4;
243e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_DATA5 = Tables.DATA + "." + Data.DATA5;
244e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_DATA6 = Tables.DATA + "." + Data.DATA6;
245e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_DATA7 = Tables.DATA + "." + Data.DATA7;
246e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_DATA8 = Tables.DATA + "." + Data.DATA8;
247e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_DATA9 = Tables.DATA + "." + Data.DATA9;
248e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_DATA10 = Tables.DATA + "." + Data.DATA10;
2490f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov        public static final String CONCRETE_DATA11 = Tables.DATA + "." + Data.DATA11;
2500f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov        public static final String CONCRETE_DATA12 = Tables.DATA + "." + Data.DATA12;
2510f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov        public static final String CONCRETE_DATA13 = Tables.DATA + "." + Data.DATA13;
2520f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov        public static final String CONCRETE_DATA14 = Tables.DATA + "." + Data.DATA14;
2530f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov        public static final String CONCRETE_DATA15 = Tables.DATA + "." + Data.DATA15;
254e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_IS_PRIMARY = Tables.DATA + "." + Data.IS_PRIMARY;
255e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    }
256e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
2570f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov    // Used only for legacy API support
2580f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov    public interface ExtensionsColumns {
2590f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov        public static final String NAME = Data.DATA1;
2600f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov        public static final String VALUE = Data.DATA2;
2610f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov    }
2620f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov
2630f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov    public interface GroupMembershipColumns {
2640f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov        public static final String CONTACT_ID = Data.CONTACT_ID;
2650f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov        public static final String GROUP_ROW_ID = GroupMembership.GROUP_ROW_ID;
2660f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov    }
2670f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov
268e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    public interface PhoneColumns {
269e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String NORMALIZED_NUMBER = Data.DATA4;
270e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public static final String CONCRETE_NORMALIZED_NUMBER = DataColumns.CONCRETE_DATA4;
271ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
272ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
273ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public interface GroupsColumns {
27467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String PACKAGE_ID = "package_id";
27567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
276ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String CONCRETE_ID = Tables.GROUPS + "." + BaseColumns._ID;
27767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String CONCRETE_SOURCE_ID = Tables.GROUPS + "." + Groups.SOURCE_ID;
27867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey}
279b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
280b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    public interface ActivitiesColumns {
281b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String PACKAGE_ID = "package_id";
282b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String MIMETYPE_ID = "mimetype_id";
283b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
284b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
285b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    public interface PhoneLookupColumns {
286b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String _ID = BaseColumns._ID;
287b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String DATA_ID = "data_id";
288b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String CONTACT_ID = "contact_id";
289b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String NORMALIZED_NUMBER = "normalized_number";
290b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
291b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
292a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    public interface NameLookupColumns {
293a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        public static final String _ID = BaseColumns._ID;
294a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        public static final String CONTACT_ID = "contact_id";
295a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        public static final String NORMALIZED_NAME = "normalized_name";
296a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        public static final String NAME_TYPE = "name_type";
297a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
298a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
299a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov    public final static class NameLookupType {
300a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        public static final int FULL_NAME = 0;
301a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        public static final int FULL_NAME_CONCATENATED = 1;
302a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        public static final int FULL_NAME_REVERSE = 2;
303a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        public static final int FULL_NAME_REVERSE_CONCATENATED = 3;
304b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public static final int FULL_NAME_WITH_NICKNAME = 4;
305b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public static final int FULL_NAME_WITH_NICKNAME_REVERSE = 5;
306b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public static final int GIVEN_NAME_ONLY = 6;
307b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public static final int GIVEN_NAME_ONLY_AS_NICKNAME = 7;
308b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public static final int FAMILY_NAME_ONLY = 8;
309b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public static final int FAMILY_NAME_ONLY_AS_NICKNAME = 9;
310b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public static final int NICKNAME = 10;
311a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov        public static final int EMAIL_BASED_NICKNAME = 11;
312a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
313a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov        // This is the highest name lookup type code plus one
314a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov        public static final int TYPE_COUNT = 12;
315a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov
316a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov        public static boolean isBasedOnStructuredName(int nameLookupType) {
317a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov            return nameLookupType != NameLookupType.EMAIL_BASED_NICKNAME
318a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov                    && nameLookupType != NameLookupType.NICKNAME;
319a5ad551e1753086825499f1aeb6415bb986f3588Dmitri Plotnikov        }
320a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
321a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
322ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public interface PackagesColumns {
323b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String _ID = BaseColumns._ID;
324b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String PACKAGE = "package";
325b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
326b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
327ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public interface MimetypesColumns {
328b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String _ID = BaseColumns._ID;
329b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        public static final String MIMETYPE = "mimetype";
330ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
331ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String CONCRETE_ID = Tables.MIMETYPES + "." + BaseColumns._ID;
332ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        public static final String CONCRETE_MIMETYPE = Tables.MIMETYPES + "." + MIMETYPE;
333b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
334b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
335b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    public interface AggregationExceptionColumns {
336b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        public static final String _ID = BaseColumns._ID;
337127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        public static final String CONTACT_ID1 = "contact_id1";
338127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        public static final String CONTACT_ID2 = "contact_id2";
339b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    }
340b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
341b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    public interface NicknameLookupColumns {
342b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public static final String NAME = "name";
343b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public static final String CLUSTER = "cluster";
344b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    }
345b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
346b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    private static final String[] NICKNAME_LOOKUP_COLUMNS = new String[] {
347b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        NicknameLookupColumns.CLUSTER
348b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    };
349b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
350b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    private static final int COL_NICKNAME_LOOKUP_CLUSTER = 0;
351b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
352b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    /** In-memory cache of previously found mimetype mappings */
353bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov    private final HashMap<String, Long> mMimetypeCache = new HashMap<String, Long>();
354b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    /** In-memory cache of previously found package name mappings */
355bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov    private final HashMap<String, Long> mPackageCache = new HashMap<String, Long>();
356b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
357b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
358b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    /** Compiled statements for querying and inserting mappings */
359b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private SQLiteStatement mMimetypeQuery;
360b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private SQLiteStatement mPackageQuery;
3616bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov    private SQLiteStatement mAggregateIdQuery;
362f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private SQLiteStatement mAggregationModeQuery;
36361bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov    private SQLiteStatement mAggregateIdUpdate;
364b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private SQLiteStatement mMimetypeInsert;
365b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private SQLiteStatement mPackageInsert;
36661bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov    private SQLiteStatement mNameLookupInsert;
367b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
368b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private SQLiteStatement mDataMimetypeQuery;
369b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private SQLiteStatement mActivitiesMimetypeQuery;
370b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
371b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    private final Context mContext;
37235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana    private final SyncStateContentProviderHelper mSyncState;
373b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    private HashMap<String, String[]> mNicknameClusterCache;
374b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
375ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Compiled statements for updating {@link Aggregates#IN_VISIBLE_GROUP}. */
376ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private SQLiteStatement mVisibleAllUpdate;
377ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private SQLiteStatement mVisibleSpecificUpdate;
378ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
379b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private static OpenHelper sSingleton = null;
380b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
381b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    public static synchronized OpenHelper getInstance(Context context) {
382b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        if (sSingleton == null) {
383b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            sSingleton = new OpenHelper(context);
384b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        }
385b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        return sSingleton;
386b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
387b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
3881f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    /**
38931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov     * Private constructor, callers except unit tests should obtain an instance through
39035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana     * {@link #getInstance(android.content.Context)} instead.
3911f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     */
39231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    /* package */ OpenHelper(Context context) {
393b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        super(context, DATABASE_NAME, null, DATABASE_VERSION);
394b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        Log.i(TAG, "Creating OpenHelper");
395619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
396b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        mContext = context;
39728b3769e3fcecae56c3fc70cbcb0f95282b9640eFred Quintana        mSyncState = new SyncStateContentProviderHelper();
398b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
399b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
400b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    @Override
401b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    public void onOpen(SQLiteDatabase db) {
40235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        mSyncState.onDatabaseOpened(db);
40335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
404b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // Create compiled statements for package and mimetype lookups
405ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mMimetypeQuery = db.compileStatement("SELECT " + MimetypesColumns._ID + " FROM "
406ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Tables.MIMETYPES + " WHERE " + MimetypesColumns.MIMETYPE + "=?");
407ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mPackageQuery = db.compileStatement("SELECT " + PackagesColumns._ID + " FROM "
408ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Tables.PACKAGES + " WHERE " + PackagesColumns.PACKAGE + "=?");
4096bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov        mAggregateIdQuery = db.compileStatement("SELECT " + Contacts.AGGREGATE_ID + " FROM "
4106bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov                + Tables.CONTACTS + " WHERE " + Contacts._ID + "=?");
41161bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov        mAggregateIdUpdate = db.compileStatement("UPDATE " + Tables.CONTACTS + " SET "
41261bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov                + Contacts.AGGREGATE_ID + "=?" + " WHERE " + Contacts._ID + "=?");
413f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        mAggregationModeQuery = db.compileStatement("SELECT " + Contacts.AGGREGATION_MODE + " FROM "
414f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                + Tables.CONTACTS + " WHERE " + Contacts._ID + "=?");
415ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mMimetypeInsert = db.compileStatement("INSERT INTO " + Tables.MIMETYPES + "("
416ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + MimetypesColumns.MIMETYPE + ") VALUES (?)");
417ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mPackageInsert = db.compileStatement("INSERT INTO " + Tables.PACKAGES + "("
418ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + PackagesColumns.PACKAGE + ") VALUES (?)");
419ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
420ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mDataMimetypeQuery = db.compileStatement("SELECT " + MimetypesColumns.MIMETYPE + " FROM "
421ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Tables.DATA_JOIN_MIMETYPES + " WHERE " + Tables.DATA + "." + Data._ID + "=?");
422ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mActivitiesMimetypeQuery = db.compileStatement("SELECT " + MimetypesColumns.MIMETYPE
423ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + " FROM " + Tables.ACTIVITIES_JOIN_MIMETYPES + " WHERE " + Tables.ACTIVITIES + "."
424b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                + Activities._ID + "=?");
42561bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov        mNameLookupInsert = db.compileStatement("INSERT INTO " + Tables.NAME_LOOKUP + "("
42661bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov                + NameLookupColumns.CONTACT_ID + "," + NameLookupColumns.NAME_TYPE + ","
42761bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov                + NameLookupColumns.NORMALIZED_NAME + ") VALUES (?,?,?)");
4281f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
429ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final String visibleUpdate = "UPDATE " + Tables.AGGREGATES + " SET "
430ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + Aggregates.IN_VISIBLE_GROUP + "= (" + Clauses.IN_VISIBLE_GROUP + ")";
431ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
432ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mVisibleAllUpdate = db.compileStatement(visibleUpdate);
433ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mVisibleSpecificUpdate = db.compileStatement(visibleUpdate + " WHERE "
434ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                + AggregatesColumns.CONCRETE_ID + "=?");
435ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
4361f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        // Make sure we have an in-memory presence table
4371f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        final String tableName = DATABASE_PRESENCE + "." + Tables.PRESENCE;
4381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        final String indexName = DATABASE_PRESENCE + ".presenceIndex";
4391f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
4401f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        db.execSQL("ATTACH DATABASE ':memory:' AS " + DATABASE_PRESENCE + ";");
4411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        db.execSQL("CREATE TABLE IF NOT EXISTS " + tableName + " ("+
4421f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                BaseColumns._ID + " INTEGER PRIMARY KEY," +
4431f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                Presence.AGGREGATE_ID + " INTEGER REFERENCES aggregates(_id)," +
4441f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                Presence.DATA_ID + " INTEGER REFERENCES data(_id)," +
4451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                Presence.IM_PROTOCOL + " TEXT," +
4461f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                Presence.IM_HANDLE + " TEXT," +
4471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                Presence.IM_ACCOUNT + " TEXT," +
4481f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                Presence.PRESENCE_STATUS + " INTEGER," +
4491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                Presence.PRESENCE_CUSTOM_STATUS + " TEXT," +
4501f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                "UNIQUE(" + Presence.IM_PROTOCOL + ", " + Presence.IM_HANDLE + ", " + Presence.IM_ACCOUNT + ")" +
4511f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        ");");
4521f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
453fb241add950ad1314dff339805cb9eb2d6136f96Jeff Sharkey        db.execSQL("CREATE INDEX IF NOT EXISTS " + indexName + " ON " + Tables.PRESENCE + " ("
4541f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                + Presence.AGGREGATE_ID + ");");
455b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
456b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
457b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    @Override
458b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    public void onCreate(SQLiteDatabase db) {
459b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        Log.i(TAG, "Bootstrapping database");
460b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
46135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        mSyncState.createDatabase(db);
46235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
463b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // One row per group of contacts corresponding to the same person
464b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        db.execSQL("CREATE TABLE " + Tables.AGGREGATES + " (" +
465b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
466b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Aggregates.DISPLAY_NAME + " TEXT," +
467f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Aggregates.PHOTO_ID + " INTEGER REFERENCES data(_id)," +
468f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Aggregates.CUSTOM_RINGTONE + " TEXT," +
469f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Aggregates.SEND_TO_VOICEMAIL + " INTEGER NOT NULL DEFAULT 0," +
470f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Aggregates.TIMES_CONTACTED + " INTEGER NOT NULL DEFAULT 0," +
471b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Aggregates.LAST_TIME_CONTACTED + " INTEGER," +
472f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Aggregates.STARRED + " INTEGER NOT NULL DEFAULT 0," +
473f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Aggregates.IN_VISIBLE_GROUP + " INTEGER NOT NULL DEFAULT 1," +
474619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                AggregatesColumns.OPTIMAL_PRIMARY_PHONE_ID + " INTEGER REFERENCES data(_id)," +
47567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                AggregatesColumns.OPTIMAL_PRIMARY_PHONE_IS_RESTRICTED + " INTEGER DEFAULT 0," +
476619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                AggregatesColumns.FALLBACK_PRIMARY_PHONE_ID + " INTEGER REFERENCES data(_id)," +
477619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_ID + " INTEGER REFERENCES data(_id)," +
47867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                AggregatesColumns.OPTIMAL_PRIMARY_EMAIL_IS_RESTRICTED + " INTEGER DEFAULT 0," +
479619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                AggregatesColumns.FALLBACK_PRIMARY_EMAIL_ID + " INTEGER REFERENCES data(_id)," +
48067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                AggregatesColumns.SINGLE_IS_RESTRICTED + " INTEGER REFERENCES package(_id)" +
481b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        ");");
482b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
483b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // Contacts table
484b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        db.execSQL("CREATE TABLE " + Tables.CONTACTS + " (" +
485b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Contacts._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
48667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                Contacts.IS_RESTRICTED + " INTEGER DEFAULT 0," +
487035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                Contacts.ACCOUNT_NAME + " STRING DEFAULT NULL, " +
488035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                Contacts.ACCOUNT_TYPE + " STRING DEFAULT NULL, " +
4897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                Contacts.SOURCE_ID + " TEXT," +
4907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                Contacts.VERSION + " INTEGER NOT NULL DEFAULT 1," +
4917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                Contacts.DIRTY + " INTEGER NOT NULL DEFAULT 1," +
492f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Contacts.AGGREGATE_ID + " INTEGER," +
493f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Contacts.AGGREGATION_MODE + " INTEGER NOT NULL DEFAULT " +
494f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                        Contacts.AGGREGATION_MODE_DEFAULT + "," +
495f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Contacts.CUSTOM_RINGTONE + " TEXT," +
496f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Contacts.SEND_TO_VOICEMAIL + " INTEGER NOT NULL DEFAULT 0," +
497f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Contacts.TIMES_CONTACTED + " INTEGER NOT NULL DEFAULT 0," +
498f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                Contacts.LAST_TIME_CONTACTED + " INTEGER," +
4993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                Contacts.STARRED + " INTEGER INTEGER NOT NULL DEFAULT 0," +
5003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                ContactsColumns.DISPLAY_NAME + " TEXT" +
501b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        ");");
502b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
503b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // Package name mapping table
504ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        db.execSQL("CREATE TABLE " + Tables.PACKAGES + " (" +
505ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                PackagesColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
506ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                PackagesColumns.PACKAGE + " TEXT NOT NULL" +
507b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        ");");
508b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
509ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Mimetype mapping table
510ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        db.execSQL("CREATE TABLE " + Tables.MIMETYPES + " (" +
511ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                MimetypesColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
512ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                MimetypesColumns.MIMETYPE + " TEXT NOT NULL" +
513b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        ");");
514b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
515b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // Public generic data table
516b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        db.execSQL("CREATE TABLE " + Tables.DATA + " (" +
517b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Data._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
51867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                DataColumns.PACKAGE_ID + " INTEGER REFERENCES package(_id)," +
519b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                DataColumns.MIMETYPE_ID + " INTEGER REFERENCES mimetype(_id) NOT NULL," +
520b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Data.CONTACT_ID + " INTEGER NOT NULL," +
521f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.IS_PRIMARY + " INTEGER NOT NULL DEFAULT 0," +
522f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.IS_SUPER_PRIMARY + " INTEGER NOT NULL DEFAULT 0," +
523f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.DATA_VERSION + " INTEGER NOT NULL DEFAULT 0," +
524f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.DATA1 + " TEXT," +
525f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.DATA2 + " TEXT," +
526f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.DATA3 + " TEXT," +
527f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.DATA4 + " TEXT," +
528f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.DATA5 + " TEXT," +
529f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.DATA6 + " TEXT," +
530f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.DATA7 + " TEXT," +
531f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.DATA8 + " TEXT," +
532f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                Data.DATA9 + " TEXT," +
53367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                Data.DATA10 + " TEXT," +
53467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                Data.DATA11 + " TEXT," +
53567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                Data.DATA12 + " TEXT," +
53667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                Data.DATA13 + " TEXT," +
53767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                Data.DATA14 + " TEXT," +
53867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                Data.DATA15 + " TEXT" +
539b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        ");");
540b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
541f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        /**
542f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana         * set contact.dirty whenever the contact is updated and the new version does not explicity
543f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana         * clear the dirty flag
544f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana         *
545f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana         * Want to have a data row that has the server version of the contact. Then when I save
546f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana         * an entry from the server into the provider I will set the server version of the data
547f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana         * while also clearing the dirty flag of the contact.
548f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana         *
549f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana         * increment the contact.version whenever the contact is updated
550f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana         */
551f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        db.execSQL("CREATE TRIGGER " + Tables.CONTACTS + "_updated1 "
552f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "   BEFORE UPDATE ON " + Tables.CONTACTS
553f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + " BEGIN "
554f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "   UPDATE " + Tables.CONTACTS
555f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "     SET "
556f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                +         Contacts.VERSION + "=OLD." + Contacts.VERSION + "+1, "
557f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                +         Contacts.DIRTY + "=1"
558f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "     WHERE " + Contacts._ID + "=OLD." + Contacts._ID + ";"
559f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + " END");
560f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana
561f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        db.execSQL("CREATE TRIGGER " + Tables.CONTACTS + "_deleted "
562f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "   BEFORE DELETE ON " + Tables.CONTACTS
563f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + " BEGIN "
564f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "   DELETE FROM " + Tables.DATA
565f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "     WHERE " + Data.CONTACT_ID + "=OLD." + Contacts._ID + ";"
566f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "   DELETE FROM " + Tables.PHONE_LOOKUP
567f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "     WHERE " + PhoneLookupColumns.CONTACT_ID + "=OLD." + Contacts._ID + ";"
568f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + " END");
569f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana
570f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        db.execSQL("CREATE TRIGGER " + Tables.DATA + "_updated AFTER UPDATE ON " + Tables.DATA
571f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + " BEGIN "
572f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "   UPDATE " + Tables.DATA
573f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "     SET " + Data.DATA_VERSION + "=OLD." + Data.DATA_VERSION + "+1 "
574f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "     WHERE " + Data._ID + "=OLD." + Data._ID + ";"
575f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "   UPDATE " + Tables.CONTACTS
576f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "     SET " + Contacts.DIRTY + "=1"
577f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "     WHERE " + Contacts._ID + "=OLD." + Contacts._ID + ";"
578f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + " END");
579f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana
580f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana        db.execSQL("CREATE TRIGGER " + Tables.DATA + "_deleted BEFORE DELETE ON " + Tables.DATA
581f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + " BEGIN "
582f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "   UPDATE " + Tables.CONTACTS
583f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "     SET " + Contacts.DIRTY + "=1"
584f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "     WHERE " + Contacts._ID + "=OLD." + Contacts._ID + ";"
585f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "   DELETE FROM " + Tables.PHONE_LOOKUP
586f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + "     WHERE " + PhoneLookupColumns.DATA_ID + "=OLD." + Data._ID + ";"
587f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana                + " END");
588f5b20724819e51b339ff6ba5b8eb6b444cc31452Fred Quintana
589b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // Private phone numbers table used for lookup
590b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        db.execSQL("CREATE TABLE " + Tables.PHONE_LOOKUP + " (" +
591b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                PhoneLookupColumns._ID + " INTEGER PRIMARY KEY," +
592b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                PhoneLookupColumns.DATA_ID + " INTEGER REFERENCES data(_id) NOT NULL," +
593b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                PhoneLookupColumns.CONTACT_ID + " INTEGER REFERENCES contacts(_id) NOT NULL," +
594b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                PhoneLookupColumns.NORMALIZED_NUMBER + " TEXT NOT NULL" +
595b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        ");");
596b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
597b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        db.execSQL("CREATE INDEX phone_lookup_index ON " + Tables.PHONE_LOOKUP + " (" +
598b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                PhoneLookupColumns.NORMALIZED_NUMBER + " ASC, " +
599b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                PhoneLookupColumns.CONTACT_ID + ", " +
600b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                PhoneLookupColumns.DATA_ID +
601b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        ");");
602b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
603a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        // Private name/nickname table used for lookup
604a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        db.execSQL("CREATE TABLE " + Tables.NAME_LOOKUP + " (" +
605a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov                NameLookupColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
606a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov                NameLookupColumns.CONTACT_ID + " INTEGER REFERENCES contacts(_id) NOT NULL," +
607619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                NameLookupColumns.NORMALIZED_NAME + " TEXT," +
608a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov                NameLookupColumns.NAME_TYPE + " INTEGER" +
609a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        ");");
610a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
611a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        db.execSQL("CREATE INDEX name_lookup_index ON " + Tables.NAME_LOOKUP + " (" +
612a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov                NameLookupColumns.NORMALIZED_NAME + " ASC, " +
613a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov                NameLookupColumns.NAME_TYPE + " ASC, " +
61461bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov                NameLookupColumns.CONTACT_ID +
615a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        ");");
616a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
617b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        db.execSQL("CREATE TABLE " + Tables.NICKNAME_LOOKUP + " (" +
618b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                NicknameLookupColumns.NAME + " TEXT," +
619b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                NicknameLookupColumns.CLUSTER + " TEXT" +
620b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        ");");
621b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
622b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        db.execSQL("CREATE UNIQUE INDEX nickname_lookup_index ON " + Tables.NICKNAME_LOOKUP + " (" +
623b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                NicknameLookupColumns.NAME + ", " +
624b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                NicknameLookupColumns.CLUSTER +
625b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        ");");
626b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
627ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Groups table
628ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        db.execSQL("CREATE TABLE " + Tables.GROUPS + " (" +
629ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                Groups._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
63067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                GroupsColumns.PACKAGE_ID + " INTEGER REFERENCES package(_id)," +
631035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                Groups.ACCOUNT_NAME + " STRING DEFAULT NULL, " +
632035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana                Groups.ACCOUNT_TYPE + " STRING DEFAULT NULL, " +
633ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                Groups.SOURCE_ID + " TEXT," +
6349261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Groups.VERSION + " INTEGER NOT NULL DEFAULT 1," +
6359261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Groups.DIRTY + " INTEGER NOT NULL DEFAULT 1," +
636ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                Groups.TITLE + " TEXT," +
63767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                Groups.TITLE_RES + " INTEGER," +
6380f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov                Groups.NOTES + " TEXT," +
6390f8f3b3e4a6ad18c5868d0215cc137845a2ddc74Dmitri Plotnikov                Groups.SYSTEM_ID + " TEXT," +
640ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                Groups.GROUP_VISIBLE + " INTEGER" +
641ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        ");");
642ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
6439261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        db.execSQL("CREATE TRIGGER " + Tables.GROUPS + "_updated1 "
6449261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "   BEFORE UPDATE ON " + Tables.GROUPS
6459261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + " BEGIN "
6469261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "   UPDATE " + Tables.GROUPS
6479261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "     SET "
6489261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                +         Groups.VERSION + "=OLD." + Groups.VERSION + "+1, "
6499261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                +         Groups.DIRTY + "=1"
6509261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + "     WHERE " + Groups._ID + "=OLD." + Groups._ID + ";"
6519261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                + " END");
6529261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
653b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        db.execSQL("CREATE TABLE IF NOT EXISTS " + Tables.AGGREGATION_EXCEPTIONS + " (" +
654b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AggregationExceptionColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
655b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AggregationExceptions.TYPE + " INTEGER NOT NULL, " +
656127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                AggregationExceptionColumns.CONTACT_ID1 + " INTEGER REFERENCES contacts(_id), " +
657127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                AggregationExceptionColumns.CONTACT_ID2 + " INTEGER REFERENCES contacts(_id)" +
658b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov		");");
659b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
660b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS aggregation_exception_index1 ON " +
661b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                Tables.AGGREGATION_EXCEPTIONS + " (" +
662127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                AggregationExceptionColumns.CONTACT_ID1 + ", " +
663127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                AggregationExceptionColumns.CONTACT_ID2 +
664b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        ");");
665b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
666b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS aggregation_exception_index2 ON " +
667b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                Tables.AGGREGATION_EXCEPTIONS + " (" +
668127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                AggregationExceptionColumns.CONTACT_ID2 + ", " +
669127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov                AggregationExceptionColumns.CONTACT_ID1 +
670b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        ");");
671b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
672b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // Activities table
673b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        db.execSQL("CREATE TABLE " + Tables.ACTIVITIES + " (" +
674b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Activities._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
67567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                ActivitiesColumns.PACKAGE_ID + " INTEGER REFERENCES package(_id)," +
676b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                ActivitiesColumns.MIMETYPE_ID + " INTEGER REFERENCES mimetype(_id) NOT NULL," +
677b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Activities.RAW_ID + " TEXT," +
678499791a4f9ab29fa94ff48dd7acff55b2ac089a7Dmitri Plotnikov                Activities.IN_REPLY_TO + " TEXT," +
679b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Activities.AUTHOR_CONTACT_ID +  " INTEGER REFERENCES contacts(_id)," +
680b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Activities.TARGET_CONTACT_ID + " INTEGER REFERENCES contacts(_id)," +
681b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Activities.PUBLISHED + " INTEGER NOT NULL," +
682499791a4f9ab29fa94ff48dd7acff55b2ac089a7Dmitri Plotnikov                Activities.THREAD_PUBLISHED + " INTEGER NOT NULL," +
683b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Activities.TITLE + " TEXT NOT NULL," +
684b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Activities.SUMMARY + " TEXT," +
685adb55c2d8295d300961d86a3605c8ddc469cd4a2Dmitri Plotnikov                Activities.LINK + " TEXT, " +
686b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                Activities.THUMBNAIL + " BLOB" +
687b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        ");");
688b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
689b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        loadNicknameLookupTable(db);
690b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
691b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
692b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    @Override
693b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
6947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        Log.i(TAG, "Upgrading from version " + oldVersion + " to " + newVersion
695b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                + ", data will be lost!");
696b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
6977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        db.execSQL("DROP TABLE IF EXISTS " + Tables.ACCOUNTS + ";");
698b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        db.execSQL("DROP TABLE IF EXISTS " + Tables.AGGREGATES + ";");
699b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        db.execSQL("DROP TABLE IF EXISTS " + Tables.CONTACTS + ";");
700ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        db.execSQL("DROP TABLE IF EXISTS " + Tables.PACKAGES + ";");
701ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        db.execSQL("DROP TABLE IF EXISTS " + Tables.MIMETYPES + ";");
702b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        db.execSQL("DROP TABLE IF EXISTS " + Tables.DATA + ";");
703b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        db.execSQL("DROP TABLE IF EXISTS " + Tables.PHONE_LOOKUP + ";");
704a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        db.execSQL("DROP TABLE IF EXISTS " + Tables.NAME_LOOKUP + ";");
705b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        db.execSQL("DROP TABLE IF EXISTS " + Tables.NICKNAME_LOOKUP + ";");
706ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        db.execSQL("DROP TABLE IF EXISTS " + Tables.GROUPS + ";");
707b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        db.execSQL("DROP TABLE IF EXISTS " + Tables.ACTIVITIES + ";");
708b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
709d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // TODO: we should not be dropping agg_exceptions and contact_options. In case that table's
710d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // schema changes, we should try to preserve the data, because it was entered by the user
711d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // and has never been synched to the server.
712d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        db.execSQL("DROP TABLE IF EXISTS " + Tables.AGGREGATION_EXCEPTIONS + ";");
713b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
714b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        onCreate(db);
71535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
716f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        // TODO: eventually when this supports upgrades we should do something like the following:
71735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana//        if (!upgradeDatabase(db, oldVersion, newVersion)) {
71835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana//            mSyncState.discardSyncData(db, null /* all accounts */);
71935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana//            ContentResolver.requestSync(null /* all accounts */,
72035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana//                    mContentUri.getAuthority(), new Bundle());
72135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana//        }
722b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
723b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
724a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
725a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Wipes all data except mime type and package lookup tables.
726a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
727a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    public void wipeData() {
728a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        SQLiteDatabase db = getWritableDatabase();
729a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        db.execSQL("DELETE FROM " + Tables.AGGREGATES + ";");
730a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        db.execSQL("DELETE FROM " + Tables.CONTACTS + ";");
731a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        db.execSQL("DELETE FROM " + Tables.DATA + ";");
732a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        db.execSQL("DELETE FROM " + Tables.PHONE_LOOKUP + ";");
733a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        db.execSQL("DELETE FROM " + Tables.NAME_LOOKUP + ";");
734ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        db.execSQL("DELETE FROM " + Tables.GROUPS + ";");
735b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        db.execSQL("DELETE FROM " + Tables.AGGREGATION_EXCEPTIONS + ";");
736a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        db.execSQL("DELETE FROM " + Tables.ACTIVITIES + ";");
737b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
738b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        // Note: we are not removing reference data from Tables.NICKNAME_LOOKUP
739b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
740a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov        db.execSQL("VACUUM;");
741a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
742b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
743b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    /**
744619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Return the {@link ApplicationInfo#uid} for the given package name.
745619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
746619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public static int getUidForPackageName(PackageManager pm, String packageName) {
747619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        try {
748619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            ApplicationInfo clientInfo = pm.getApplicationInfo(packageName, 0 /* no flags */);
749619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            return clientInfo.uid;
750619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        } catch (NameNotFoundException e) {
751619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            throw new RuntimeException(e);
752619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
753619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
754619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
755619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
756b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * Perform an internal string-to-integer lookup using the compiled
757b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * {@link SQLiteStatement} provided, using the in-memory cache to speed up
758b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * lookups. If a mapping isn't found in cache or database, it will be
759b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * created. All new, uncached answers are added to the cache automatically.
760b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     *
761b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * @param query Compiled statement used to query for the mapping.
762b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * @param insert Compiled statement used to insert a new mapping when no
763b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     *            existing one is found in cache or from query.
764b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * @param value Value to find mapping for.
765b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * @param cache In-memory cache of previous answers.
766b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * @return An unique integer mapping for the given value.
767b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     */
768b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    private synchronized long getCachedId(SQLiteStatement query, SQLiteStatement insert,
769b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            String value, HashMap<String, Long> cache) {
770b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // Try an in-memory cache lookup
771b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        if (cache.containsKey(value)) {
772b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            return cache.get(value);
773b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        }
774b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
775b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        long id = -1;
776b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        try {
777b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            // Try searching database for mapping
778b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            DatabaseUtils.bindObjectToProgram(query, 1, value);
779b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            id = query.simpleQueryForLong();
780b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        } catch (SQLiteDoneException e) {
781b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            // Nothing found, so try inserting new mapping
782b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            DatabaseUtils.bindObjectToProgram(insert, 1, value);
783b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            id = insert.executeInsert();
784b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        }
785b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
786b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        if (id != -1) {
787b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            // Cache and return the new answer
788b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            cache.put(value, id);
789b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            return id;
790b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        } else {
791b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            // Otherwise throw if no mapping found or created
792b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            throw new IllegalStateException("Couldn't find or create internal "
793b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey                    + "lookup table entry for value " + value);
794b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        }
795b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
796b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
797b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    /**
798ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Convert a package name into an integer, using {@link Tables#PACKAGES} for
799b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * lookups and possible allocation of new IDs as needed.
800b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     */
801b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    public long getPackageId(String packageName) {
802b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // Make sure compiled statements are ready by opening database
803b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        getReadableDatabase();
804b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        return getCachedId(mPackageQuery, mPackageInsert, packageName, mPackageCache);
805b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
806b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
807b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    /**
808ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Convert a mimetype into an integer, using {@link Tables#MIMETYPES} for
809b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * lookups and possible allocation of new IDs as needed.
810b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     */
811b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    public long getMimeTypeId(String mimetype) {
812b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // Make sure compiled statements are ready by opening database
813b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        getReadableDatabase();
814b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        return getCachedId(mMimetypeQuery, mMimetypeInsert, mimetype, mMimetypeCache);
815b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
816b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
817b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    /**
818ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Find the mimetype for the given {@link Data#_ID}.
819b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     */
820b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    public String getDataMimeType(long dataId) {
821b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // Make sure compiled statements are ready by opening database
822b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        getReadableDatabase();
823b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        try {
824b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            // Try database query to find mimetype
825b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            DatabaseUtils.bindObjectToProgram(mDataMimetypeQuery, 1, dataId);
826b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            String mimetype = mDataMimetypeQuery.simpleQueryForString();
827b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            return mimetype;
828b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        } catch (SQLiteDoneException e) {
829b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            // No valid mapping found, so return null
830b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            return null;
831b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        }
832b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
833b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey
834b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    /**
835b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     * Find the mime-type for the given {@link Activities#_ID}.
836b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey     */
837b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    public String getActivityMimeType(long activityId) {
838b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        // Make sure compiled statements are ready by opening database
839b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        getReadableDatabase();
840b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        try {
841b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            // Try database query to find mimetype
842b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            DatabaseUtils.bindObjectToProgram(mActivitiesMimetypeQuery, 1, activityId);
843b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            String mimetype = mActivitiesMimetypeQuery.simpleQueryForString();
844b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            return mimetype;
845b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        } catch (SQLiteDoneException e) {
846b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            // No valid mapping found, so return null
847b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey            return null;
848b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey        }
849b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey    }
8506bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov
8516bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov    /**
852ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Update {@link Aggregates#IN_VISIBLE_GROUP} for all aggregates.
853ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
854ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public void updateAllVisible() {
855ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final long groupMembershipMimetypeId = getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
856ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mVisibleAllUpdate.bindLong(1, groupMembershipMimetypeId);
857ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mVisibleAllUpdate.execute();
858ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
859ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
860ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
861ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Update {@link Aggregates#IN_VISIBLE_GROUP} for a specific aggregate.
862ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
863ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public void updateAggregateVisible(long aggId) {
864ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final long groupMembershipMimetypeId = getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
865ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mVisibleSpecificUpdate.bindLong(1, groupMembershipMimetypeId);
866ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mVisibleSpecificUpdate.bindLong(2, aggId);
867ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        mVisibleSpecificUpdate.execute();
868ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
869ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
870ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
87161bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov     * Updates the aggregate ID for the specified contact.
87261bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov     */
87361bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov    public void setAggregateId(long contactId, long aggregateId) {
87461bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov        getWritableDatabase();
87561bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov        DatabaseUtils.bindObjectToProgram(mAggregateIdUpdate, 1, aggregateId);
87661bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov        DatabaseUtils.bindObjectToProgram(mAggregateIdUpdate, 2, contactId);
87761bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov        mAggregateIdUpdate.execute();
87861bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov    }
87961bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov
88061bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov    /**
8816bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov     * Returns aggregate ID for the given contact or zero if it is NULL.
8826bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov     */
8836bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov    public long getAggregateId(long contactId) {
8846bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov        getReadableDatabase();
8856bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov        try {
8866bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov            DatabaseUtils.bindObjectToProgram(mAggregateIdQuery, 1, contactId);
8876bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov            return mAggregateIdQuery.simpleQueryForLong();
8886bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov        } catch (SQLiteDoneException e) {
8896bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov            // No valid mapping found, so return -1
8906bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov            return 0;
8916bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov        }
8926bccc079d8fea5c51f9fa6fd06044bd8f5109c6fDmitri Plotnikov    }
89361bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov
894f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    public int getAggregationMode(long contactId) {
895f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        getReadableDatabase();
896f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        try {
897f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            DatabaseUtils.bindObjectToProgram(mAggregationModeQuery, 1, contactId);
898f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            return (int)mAggregationModeQuery.simpleQueryForLong();
899f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        } catch (SQLiteDoneException e) {
900f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            // No valid mapping found, so return "disabled"
901f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            return Contacts.AGGREGATION_MODE_DISABLED;
902f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        }
903f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
904f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
90561bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov    /**
90661bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov     * Inserts a record in the {@link Tables#NAME_LOOKUP} table.
90761bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov     */
90861bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov    public void insertNameLookup(long contactId, int lookupType, String name) {
90961bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov        getWritableDatabase();
91061bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov        DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 1, contactId);
91161bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov        DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 2, lookupType);
91261bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov        DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 3, name);
91361bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov        mNameLookupInsert.executeInsert();
91461bbb2287e8102b7e03922c03809c34b7b317d1cDmitri Plotnikov    }
915619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
916bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov    public static void buildPhoneLookupQuery(SQLiteQueryBuilder qb, final String number) {
917bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov        final String normalizedNumber = PhoneNumberUtils.toCallerIDMinMatch(number);
918bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov        final StringBuilder tables = new StringBuilder();
919bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov        tables.append("contacts, (SELECT data_id FROM phone_lookup "
920bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov                + "WHERE (phone_lookup.normalized_number GLOB '");
921bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov        tables.append(normalizedNumber);
922ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        tables.append("*')) AS lookup, " + Tables.DATA_JOIN_MIMETYPES);
923bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov        qb.setTables(tables.toString());
924bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov        qb.appendWhere("lookup.data_id=data._id AND data.contact_id=contacts._id AND ");
925bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov        qb.appendWhere("PHONE_NUMBERS_EQUAL(data." + Phone.NUMBER + ", ");
926bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov        qb.appendWhereEscapeString(number);
927bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov        qb.appendWhere(")");
928bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov    }
929bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov
930bf659107617a6291ba8bfeebc3f2e50138075ab5Dmitri Plotnikov
931619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
932b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov     * Loads common nickname mappings into the database.
933b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov     */
934b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    private void loadNicknameLookupTable(SQLiteDatabase db) {
93528f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar        String[] strings = mContext.getResources().getStringArray(
93628f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar                com.android.internal.R.array.common_nicknames);
937b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        if (strings == null || strings.length == 0) {
938b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            return;
939b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        }
940b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
941b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        SQLiteStatement nicknameLookupInsert = db.compileStatement("INSERT INTO "
942b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                + Tables.NICKNAME_LOOKUP + "(" + NicknameLookupColumns.NAME + ","
943b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                + NicknameLookupColumns.CLUSTER + ") VALUES (?,?)");
944b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
945b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        for (int clusterId = 0; clusterId < strings.length; clusterId++) {
946b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            String[] names = strings[clusterId].split(",");
947b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            for (int j = 0; j < names.length; j++) {
948b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                String name = NameNormalizer.normalize(names[j]);
949b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                try {
950b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                    DatabaseUtils.bindObjectToProgram(nicknameLookupInsert, 1, name);
951b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                    DatabaseUtils.bindObjectToProgram(nicknameLookupInsert, 2,
952b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                            String.valueOf(clusterId));
953b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                    nicknameLookupInsert.executeInsert();
954b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                } catch (SQLiteException e) {
955b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
956b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                    // Print the exception and keep going - this is not a fatal error
957b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                    Log.e(TAG, "Cannot insert nickname: " + names[j], e);
958b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                }
959b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            }
960b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        }
961b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    }
962b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
963b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    /**
964b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov     * Returns common nickname cluster IDs for a given name. For example, it
965b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov     * will return the same value for "Robert", "Bob" and "Rob". Some names belong to multiple
966b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov     * clusters, e.g. Leo could be Leonard or Leopold.
967b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov     *
968b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov     * May return null.
969b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov     *
970b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov     * @param normalizedName A normalized first name, see {@link NameNormalizer#normalize}.
971b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov     */
972b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    public String[] getCommonNicknameClusters(String normalizedName) {
973b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        if (mNicknameClusterCache == null) {
974b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            mNicknameClusterCache = new HashMap<String, String[]>();
975b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        }
976b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
977b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        synchronized (mNicknameClusterCache) {
978b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            if (mNicknameClusterCache.containsKey(normalizedName)) {
979b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                return mNicknameClusterCache.get(normalizedName);
980b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            }
981b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        }
982b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
983b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        String[] clusters = null;
984b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        SQLiteDatabase db = getReadableDatabase();
985b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
986b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        Cursor cursor = db.query(Tables.NICKNAME_LOOKUP, NICKNAME_LOOKUP_COLUMNS,
987b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                NicknameLookupColumns.NAME + "=?", new String[] { normalizedName },
988b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                null, null, null);
989b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        try {
990b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            int count = cursor.getCount();
991b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            if (count > 0) {
992b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                clusters = new String[count];
993b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                for (int i = 0; i < count; i++) {
994b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                    cursor.moveToNext();
995b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                    clusters[i] = cursor.getString(COL_NICKNAME_LOOKUP_CLUSTER);
996b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov                }
997b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            }
998b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        } finally {
999b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            cursor.close();
1000b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        }
1001b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
1002b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        synchronized (mNicknameClusterCache) {
1003b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            mNicknameClusterCache.put(normalizedName, clusters);
1004b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        }
1005b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
1006b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        return clusters;
1007b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov    }
1008b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
1009f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    public static void copyStringValue(ContentValues toValues, String toKey,
1010f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            ContentValues fromValues, String fromKey) {
1011f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        if (fromValues.containsKey(fromKey)) {
1012f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            toValues.put(toKey, fromValues.getAsString(fromKey));
1013f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        }
1014f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
1015f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
1016f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    public static void copyLongValue(ContentValues toValues, String toKey,
1017f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            ContentValues fromValues, String fromKey) {
1018f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        if (fromValues.containsKey(fromKey)) {
1019f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            long longValue;
1020f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            Object value = fromValues.get(fromKey);
1021f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            if (value instanceof Boolean) {
1022f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                if ((Boolean)value) {
1023f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                    longValue = 1;
1024f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                } else {
1025f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                    longValue = 0;
1026f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                }
1027f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            } else {
1028f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                longValue = ((Number) value).longValue();
1029f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            }
1030f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov            toValues.put(toKey, longValue);
1031f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        }
1032f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
1033f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
103435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana    public SyncStateContentProviderHelper getSyncState() {
103535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        return mSyncState;
103635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana    }
1037b650982af7aeb2800efdcea587b8ce153259cf1cJeff Sharkey}
1038