1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 package com.android.providers.contacts; 17 18 import android.accounts.Account; 19 import android.app.SearchManager; 20 import android.content.ContentUris; 21 import android.content.ContentValues; 22 import android.content.Context; 23 import android.content.UriMatcher; 24 import android.database.Cursor; 25 import android.database.DatabaseUtils; 26 import android.database.SQLException; 27 import android.database.sqlite.SQLiteDatabase; 28 import android.database.sqlite.SQLiteDoneException; 29 import android.database.sqlite.SQLiteQueryBuilder; 30 import android.database.sqlite.SQLiteStatement; 31 import android.net.Uri; 32 import android.provider.BaseColumns; 33 import android.provider.Contacts.ContactMethods; 34 import android.provider.Contacts.Extensions; 35 import android.provider.Contacts.People; 36 import android.provider.ContactsContract; 37 import android.provider.ContactsContract.CommonDataKinds.Email; 38 import android.provider.ContactsContract.CommonDataKinds.GroupMembership; 39 import android.provider.ContactsContract.CommonDataKinds.Im; 40 import android.provider.ContactsContract.CommonDataKinds.Note; 41 import android.provider.ContactsContract.CommonDataKinds.Organization; 42 import android.provider.ContactsContract.CommonDataKinds.Phone; 43 import android.provider.ContactsContract.CommonDataKinds.Photo; 44 import android.provider.ContactsContract.CommonDataKinds.StructuredName; 45 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 46 import android.provider.ContactsContract.Contacts; 47 import android.provider.ContactsContract.Data; 48 import android.provider.ContactsContract.Groups; 49 import android.provider.ContactsContract.RawContacts; 50 import android.provider.ContactsContract.Settings; 51 import android.provider.ContactsContract.StatusUpdates; 52 import android.text.TextUtils; 53 import android.util.Log; 54 55 import com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns; 56 import com.android.providers.contacts.ContactsDatabaseHelper.DataColumns; 57 import com.android.providers.contacts.ContactsDatabaseHelper.ExtensionsColumns; 58 import com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns; 59 import com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns; 60 import com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns; 61 import com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType; 62 import com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns; 63 import com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 64 import com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; 65 import com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns; 66 import com.android.providers.contacts.ContactsDatabaseHelper.Tables; 67 68 import java.util.HashMap; 69 import java.util.Locale; 70 71 @SuppressWarnings("deprecation") 72 public class LegacyApiSupport { 73 74 private static final String TAG = "ContactsProviderV1"; 75 76 private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 77 78 private static final int PEOPLE = 1; 79 private static final int PEOPLE_ID = 2; 80 private static final int PEOPLE_UPDATE_CONTACT_TIME = 3; 81 private static final int ORGANIZATIONS = 4; 82 private static final int ORGANIZATIONS_ID = 5; 83 private static final int PEOPLE_CONTACTMETHODS = 6; 84 private static final int PEOPLE_CONTACTMETHODS_ID = 7; 85 private static final int CONTACTMETHODS = 8; 86 private static final int CONTACTMETHODS_ID = 9; 87 private static final int PEOPLE_PHONES = 10; 88 private static final int PEOPLE_PHONES_ID = 11; 89 private static final int PHONES = 12; 90 private static final int PHONES_ID = 13; 91 private static final int EXTENSIONS = 14; 92 private static final int EXTENSIONS_ID = 15; 93 private static final int PEOPLE_EXTENSIONS = 16; 94 private static final int PEOPLE_EXTENSIONS_ID = 17; 95 private static final int GROUPS = 18; 96 private static final int GROUPS_ID = 19; 97 private static final int GROUPMEMBERSHIP = 20; 98 private static final int GROUPMEMBERSHIP_ID = 21; 99 private static final int PEOPLE_GROUPMEMBERSHIP = 22; 100 private static final int PEOPLE_GROUPMEMBERSHIP_ID = 23; 101 private static final int PEOPLE_PHOTO = 24; 102 private static final int PHOTOS = 25; 103 private static final int PHOTOS_ID = 26; 104 private static final int PEOPLE_FILTER = 29; 105 private static final int DELETED_PEOPLE = 30; 106 private static final int DELETED_GROUPS = 31; 107 private static final int SEARCH_SUGGESTIONS = 32; 108 private static final int SEARCH_SHORTCUT = 33; 109 private static final int PHONES_FILTER = 34; 110 private static final int LIVE_FOLDERS_PEOPLE = 35; 111 private static final int LIVE_FOLDERS_PEOPLE_GROUP_NAME = 36; 112 private static final int LIVE_FOLDERS_PEOPLE_WITH_PHONES = 37; 113 private static final int LIVE_FOLDERS_PEOPLE_FAVORITES = 38; 114 private static final int CONTACTMETHODS_EMAIL = 39; 115 private static final int GROUP_NAME_MEMBERS = 40; 116 private static final int GROUP_SYSTEM_ID_MEMBERS = 41; 117 private static final int PEOPLE_ORGANIZATIONS = 42; 118 private static final int PEOPLE_ORGANIZATIONS_ID = 43; 119 private static final int SETTINGS = 44; 120 121 private static final String PEOPLE_JOINS = 122 " JOIN " + Tables.ACCOUNTS + " ON (" 123 + RawContactsColumns.CONCRETE_ACCOUNT_ID + "=" + AccountsColumns.CONCRETE_ID + ")" 124 + " LEFT OUTER JOIN data name ON (raw_contacts._id = name.raw_contact_id" 125 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = name.mimetype_id)" 126 + "='" + StructuredName.CONTENT_ITEM_TYPE + "')" 127 + " LEFT OUTER JOIN data organization ON (raw_contacts._id = organization.raw_contact_id" 128 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = organization.mimetype_id)" 129 + "='" + Organization.CONTENT_ITEM_TYPE + "' AND organization.is_primary)" 130 + " LEFT OUTER JOIN data email ON (raw_contacts._id = email.raw_contact_id" 131 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = email.mimetype_id)" 132 + "='" + Email.CONTENT_ITEM_TYPE + "' AND email.is_primary)" 133 + " LEFT OUTER JOIN data note ON (raw_contacts._id = note.raw_contact_id" 134 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = note.mimetype_id)" 135 + "='" + Note.CONTENT_ITEM_TYPE + "')" 136 + " LEFT OUTER JOIN data phone ON (raw_contacts._id = phone.raw_contact_id" 137 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = phone.mimetype_id)" 138 + "='" + Phone.CONTENT_ITEM_TYPE + "' AND phone.is_primary)"; 139 140 public static final String DATA_JOINS = 141 " JOIN mimetypes ON (mimetypes._id = data.mimetype_id)" 142 + " JOIN raw_contacts ON (raw_contacts._id = data.raw_contact_id)" 143 + PEOPLE_JOINS; 144 145 public static final String PRESENCE_JOINS = 146 " LEFT OUTER JOIN " + Tables.PRESENCE + 147 " ON (" + Tables.PRESENCE + "." + StatusUpdates.DATA_ID + "=" + 148 "(SELECT MAX(" + StatusUpdates.DATA_ID + ")" + 149 " FROM " + Tables.PRESENCE + 150 " WHERE people._id = " + PresenceColumns.RAW_CONTACT_ID + ")" + 151 " )"; 152 153 private static final String PHONETIC_NAME_SQL = "trim(trim(" 154 + "ifnull(name." + StructuredName.PHONETIC_GIVEN_NAME + ",' ')||' '||" 155 + "ifnull(name." + StructuredName.PHONETIC_MIDDLE_NAME + ",' '))||' '||" 156 + "ifnull(name." + StructuredName.PHONETIC_FAMILY_NAME + ",' ')) "; 157 158 private static final String CONTACT_METHOD_KIND_SQL = 159 "CAST ((CASE WHEN mimetype='" + Email.CONTENT_ITEM_TYPE + "'" 160 + " THEN " + android.provider.Contacts.KIND_EMAIL 161 + " ELSE" 162 + " (CASE WHEN mimetype='" + Im.CONTENT_ITEM_TYPE +"'" 163 + " THEN " + android.provider.Contacts.KIND_IM 164 + " ELSE" 165 + " (CASE WHEN mimetype='" + StructuredPostal.CONTENT_ITEM_TYPE + "'" 166 + " THEN " + android.provider.Contacts.KIND_POSTAL 167 + " ELSE" 168 + " NULL" 169 + " END)" 170 + " END)" 171 + " END) AS INTEGER)"; 172 173 private static final String IM_PROTOCOL_SQL = 174 "(CASE WHEN " + StatusUpdates.PROTOCOL + "=" + Im.PROTOCOL_CUSTOM 175 + " THEN 'custom:'||" + StatusUpdates.CUSTOM_PROTOCOL 176 + " ELSE 'pre:'||" + StatusUpdates.PROTOCOL 177 + " END)"; 178 179 private static String CONTACT_METHOD_DATA_SQL = 180 "(CASE WHEN " + Data.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'" 181 + " THEN (CASE WHEN " + Tables.DATA + "." + Im.PROTOCOL + "=" + Im.PROTOCOL_CUSTOM 182 + " THEN 'custom:'||" + Tables.DATA + "." + Im.CUSTOM_PROTOCOL 183 + " ELSE 'pre:'||" + Tables.DATA + "." + Im.PROTOCOL 184 + " END)" 185 + " ELSE " + Tables.DATA + "." + Email.DATA 186 + " END)"; 187 188 private static final Uri LIVE_FOLDERS_CONTACTS_URI = Uri.withAppendedPath( 189 ContactsContract.AUTHORITY_URI, "live_folders/contacts"); 190 191 private static final Uri LIVE_FOLDERS_CONTACTS_WITH_PHONES_URI = Uri.withAppendedPath( 192 ContactsContract.AUTHORITY_URI, "live_folders/contacts_with_phones"); 193 194 private static final Uri LIVE_FOLDERS_CONTACTS_FAVORITES_URI = Uri.withAppendedPath( 195 ContactsContract.AUTHORITY_URI, "live_folders/favorites"); 196 197 private static final String CONTACTS_UPDATE_LASTTIMECONTACTED = 198 "UPDATE " + Tables.CONTACTS + 199 " SET " + Contacts.LAST_TIME_CONTACTED + "=? " + 200 "WHERE " + Contacts._ID + "=?"; 201 private static final String RAWCONTACTS_UPDATE_LASTTIMECONTACTED = 202 "UPDATE " + Tables.RAW_CONTACTS + " SET " 203 + RawContacts.LAST_TIME_CONTACTED + "=? WHERE " 204 + RawContacts._ID + "=?"; 205 206 private String[] mSelectionArgs1 = new String[1]; 207 private String[] mSelectionArgs2 = new String[2]; 208 209 public interface LegacyTables { 210 public static final String PEOPLE = "view_v1_people"; 211 public static final String PEOPLE_JOIN_PRESENCE = "view_v1_people people " + PRESENCE_JOINS; 212 public static final String GROUPS = "view_v1_groups"; 213 public static final String ORGANIZATIONS = "view_v1_organizations"; 214 public static final String CONTACT_METHODS = "view_v1_contact_methods"; 215 public static final String PHONES = "view_v1_phones"; 216 public static final String EXTENSIONS = "view_v1_extensions"; 217 public static final String GROUP_MEMBERSHIP = "view_v1_group_membership"; 218 public static final String PHOTOS = "view_v1_photos"; 219 public static final String SETTINGS = "v1_settings"; 220 } 221 222 private static final String[] ORGANIZATION_MIME_TYPES = new String[] { 223 Organization.CONTENT_ITEM_TYPE 224 }; 225 226 private static final String[] CONTACT_METHOD_MIME_TYPES = new String[] { 227 Email.CONTENT_ITEM_TYPE, 228 Im.CONTENT_ITEM_TYPE, 229 StructuredPostal.CONTENT_ITEM_TYPE, 230 }; 231 232 private static final String[] PHONE_MIME_TYPES = new String[] { 233 Phone.CONTENT_ITEM_TYPE 234 }; 235 236 private static final String[] PHOTO_MIME_TYPES = new String[] { 237 Photo.CONTENT_ITEM_TYPE 238 }; 239 240 private static final String[] GROUP_MEMBERSHIP_MIME_TYPES = new String[] { 241 GroupMembership.CONTENT_ITEM_TYPE 242 }; 243 244 private static final String[] EXTENSION_MIME_TYPES = new String[] { 245 android.provider.Contacts.Extensions.CONTENT_ITEM_TYPE 246 }; 247 248 private interface IdQuery { 249 String[] COLUMNS = { BaseColumns._ID }; 250 251 int _ID = 0; 252 } 253 254 /** 255 * A custom data row that is used to store legacy photo data fields no 256 * longer directly supported by the API. 257 */ 258 private interface LegacyPhotoData { 259 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo_v1_extras"; 260 261 public static final String PHOTO_DATA_ID = Data.DATA1; 262 public static final String LOCAL_VERSION = Data.DATA2; 263 public static final String DOWNLOAD_REQUIRED = Data.DATA3; 264 public static final String EXISTS_ON_SERVER = Data.DATA4; 265 public static final String SYNC_ERROR = Data.DATA5; 266 } 267 268 public static final String LEGACY_PHOTO_JOIN = 269 " LEFT OUTER JOIN data legacy_photo ON (raw_contacts._id = legacy_photo.raw_contact_id" 270 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = legacy_photo.mimetype_id)" 271 + "='" + LegacyPhotoData.CONTENT_ITEM_TYPE + "'" 272 + " AND " + DataColumns.CONCRETE_ID + " = legacy_photo." + LegacyPhotoData.PHOTO_DATA_ID 273 + ")"; 274 275 private static final HashMap<String, String> sPeopleProjectionMap; 276 private static final HashMap<String, String> sOrganizationProjectionMap; 277 private static final HashMap<String, String> sContactMethodProjectionMap; 278 private static final HashMap<String, String> sPhoneProjectionMap; 279 private static final HashMap<String, String> sExtensionProjectionMap; 280 private static final HashMap<String, String> sGroupProjectionMap; 281 private static final HashMap<String, String> sGroupMembershipProjectionMap; 282 private static final HashMap<String, String> sPhotoProjectionMap; 283 284 static { 285 286 // Contacts URI matching table 287 UriMatcher matcher = sUriMatcher; 288 289 String authority = android.provider.Contacts.AUTHORITY; 290 matcher.addURI(authority, "extensions", EXTENSIONS); 291 matcher.addURI(authority, "extensions/#", EXTENSIONS_ID); 292 matcher.addURI(authority, "groups", GROUPS); 293 matcher.addURI(authority, "groups/#", GROUPS_ID); 294 matcher.addURI(authority, "groups/name/*/members", GROUP_NAME_MEMBERS); 295 // matcher.addURI(authority, "groups/name/*/members/filter/*", 296 // GROUP_NAME_MEMBERS_FILTER); 297 matcher.addURI(authority, "groups/system_id/*/members", GROUP_SYSTEM_ID_MEMBERS); 298 // matcher.addURI(authority, "groups/system_id/*/members/filter/*", 299 // GROUP_SYSTEM_ID_MEMBERS_FILTER); 300 matcher.addURI(authority, "groupmembership", GROUPMEMBERSHIP); 301 matcher.addURI(authority, "groupmembership/#", GROUPMEMBERSHIP_ID); 302 // matcher.addURI(authority, "groupmembershipraw", GROUPMEMBERSHIP_RAW); 303 matcher.addURI(authority, "people", PEOPLE); 304 // matcher.addURI(authority, "people/strequent", PEOPLE_STREQUENT); 305 // matcher.addURI(authority, "people/strequent/filter/*", PEOPLE_STREQUENT_FILTER); 306 matcher.addURI(authority, "people/filter/*", PEOPLE_FILTER); 307 // matcher.addURI(authority, "people/with_phones_filter/*", 308 // PEOPLE_WITH_PHONES_FILTER); 309 // matcher.addURI(authority, "people/with_email_or_im_filter/*", 310 // PEOPLE_WITH_EMAIL_OR_IM_FILTER); 311 matcher.addURI(authority, "people/#", PEOPLE_ID); 312 matcher.addURI(authority, "people/#/extensions", PEOPLE_EXTENSIONS); 313 matcher.addURI(authority, "people/#/extensions/#", PEOPLE_EXTENSIONS_ID); 314 matcher.addURI(authority, "people/#/phones", PEOPLE_PHONES); 315 matcher.addURI(authority, "people/#/phones/#", PEOPLE_PHONES_ID); 316 // matcher.addURI(authority, "people/#/phones_with_presence", 317 // PEOPLE_PHONES_WITH_PRESENCE); 318 matcher.addURI(authority, "people/#/photo", PEOPLE_PHOTO); 319 // matcher.addURI(authority, "people/#/photo/data", PEOPLE_PHOTO_DATA); 320 matcher.addURI(authority, "people/#/contact_methods", PEOPLE_CONTACTMETHODS); 321 // matcher.addURI(authority, "people/#/contact_methods_with_presence", 322 // PEOPLE_CONTACTMETHODS_WITH_PRESENCE); 323 matcher.addURI(authority, "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID); 324 matcher.addURI(authority, "people/#/organizations", PEOPLE_ORGANIZATIONS); 325 matcher.addURI(authority, "people/#/organizations/#", PEOPLE_ORGANIZATIONS_ID); 326 matcher.addURI(authority, "people/#/groupmembership", PEOPLE_GROUPMEMBERSHIP); 327 matcher.addURI(authority, "people/#/groupmembership/#", PEOPLE_GROUPMEMBERSHIP_ID); 328 // matcher.addURI(authority, "people/raw", PEOPLE_RAW); 329 // matcher.addURI(authority, "people/owner", PEOPLE_OWNER); 330 matcher.addURI(authority, "people/#/update_contact_time", 331 PEOPLE_UPDATE_CONTACT_TIME); 332 matcher.addURI(authority, "deleted_people", DELETED_PEOPLE); 333 matcher.addURI(authority, "deleted_groups", DELETED_GROUPS); 334 matcher.addURI(authority, "phones", PHONES); 335 // matcher.addURI(authority, "phones_with_presence", PHONES_WITH_PRESENCE); 336 matcher.addURI(authority, "phones/filter/*", PHONES_FILTER); 337 // matcher.addURI(authority, "phones/filter_name/*", PHONES_FILTER_NAME); 338 // matcher.addURI(authority, "phones/mobile_filter_name/*", 339 // PHONES_MOBILE_FILTER_NAME); 340 matcher.addURI(authority, "phones/#", PHONES_ID); 341 matcher.addURI(authority, "photos", PHOTOS); 342 matcher.addURI(authority, "photos/#", PHOTOS_ID); 343 matcher.addURI(authority, "contact_methods", CONTACTMETHODS); 344 matcher.addURI(authority, "contact_methods/email", CONTACTMETHODS_EMAIL); 345 // matcher.addURI(authority, "contact_methods/email/*", CONTACTMETHODS_EMAIL_FILTER); 346 matcher.addURI(authority, "contact_methods/#", CONTACTMETHODS_ID); 347 // matcher.addURI(authority, "contact_methods/with_presence", 348 // CONTACTMETHODS_WITH_PRESENCE); 349 matcher.addURI(authority, "organizations", ORGANIZATIONS); 350 matcher.addURI(authority, "organizations/#", ORGANIZATIONS_ID); 351 // matcher.addURI(authority, "voice_dialer_timestamp", VOICE_DIALER_TIMESTAMP); 352 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_QUERY, 353 SEARCH_SUGGESTIONS); 354 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 355 SEARCH_SUGGESTIONS); 356 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 357 SEARCH_SHORTCUT); 358 matcher.addURI(authority, "settings", SETTINGS); 359 360 matcher.addURI(authority, "live_folders/people", LIVE_FOLDERS_PEOPLE); 361 matcher.addURI(authority, "live_folders/people/*", 362 LIVE_FOLDERS_PEOPLE_GROUP_NAME); 363 matcher.addURI(authority, "live_folders/people_with_phones", 364 LIVE_FOLDERS_PEOPLE_WITH_PHONES); 365 matcher.addURI(authority, "live_folders/favorites", 366 LIVE_FOLDERS_PEOPLE_FAVORITES); 367 368 369 HashMap<String, String> peopleProjectionMap = new HashMap<String, String>(); 370 peopleProjectionMap.put(People.NAME, People.NAME); 371 peopleProjectionMap.put(People.DISPLAY_NAME, People.DISPLAY_NAME); 372 peopleProjectionMap.put(People.PHONETIC_NAME, People.PHONETIC_NAME); 373 peopleProjectionMap.put(People.NOTES, People.NOTES); 374 peopleProjectionMap.put(People.TIMES_CONTACTED, People.TIMES_CONTACTED); 375 peopleProjectionMap.put(People.LAST_TIME_CONTACTED, People.LAST_TIME_CONTACTED); 376 peopleProjectionMap.put(People.CUSTOM_RINGTONE, People.CUSTOM_RINGTONE); 377 peopleProjectionMap.put(People.SEND_TO_VOICEMAIL, People.SEND_TO_VOICEMAIL); 378 peopleProjectionMap.put(People.STARRED, People.STARRED); 379 peopleProjectionMap.put(People.PRIMARY_ORGANIZATION_ID, People.PRIMARY_ORGANIZATION_ID); 380 peopleProjectionMap.put(People.PRIMARY_EMAIL_ID, People.PRIMARY_EMAIL_ID); 381 peopleProjectionMap.put(People.PRIMARY_PHONE_ID, People.PRIMARY_PHONE_ID); 382 383 sPeopleProjectionMap = new HashMap<String, String>(peopleProjectionMap); 384 sPeopleProjectionMap.put(People._ID, People._ID); 385 sPeopleProjectionMap.put(People.NUMBER, People.NUMBER); 386 sPeopleProjectionMap.put(People.TYPE, People.TYPE); 387 sPeopleProjectionMap.put(People.LABEL, People.LABEL); 388 sPeopleProjectionMap.put(People.NUMBER_KEY, People.NUMBER_KEY); 389 sPeopleProjectionMap.put(People.IM_PROTOCOL, IM_PROTOCOL_SQL + " AS " + People.IM_PROTOCOL); 390 sPeopleProjectionMap.put(People.IM_HANDLE, People.IM_HANDLE); 391 sPeopleProjectionMap.put(People.IM_ACCOUNT, People.IM_ACCOUNT); 392 sPeopleProjectionMap.put(People.PRESENCE_STATUS, People.PRESENCE_STATUS); 393 sPeopleProjectionMap.put(People.PRESENCE_CUSTOM_STATUS, 394 "(SELECT " + StatusUpdates.STATUS + 395 " FROM " + Tables.STATUS_UPDATES + 396 " JOIN " + Tables.DATA + 397 " ON(" + StatusUpdatesColumns.DATA_ID + "=" + DataColumns.CONCRETE_ID + ")" + 398 " WHERE " + DataColumns.CONCRETE_RAW_CONTACT_ID + "=people." + People._ID + 399 " ORDER BY " + StatusUpdates.STATUS_TIMESTAMP + " DESC " + 400 " LIMIT 1" + 401 ") AS " + People.PRESENCE_CUSTOM_STATUS); 402 403 sOrganizationProjectionMap = new HashMap<String, String>(); 404 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations._ID, 405 android.provider.Contacts.Organizations._ID); 406 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.PERSON_ID, 407 android.provider.Contacts.Organizations.PERSON_ID); 408 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.ISPRIMARY, 409 android.provider.Contacts.Organizations.ISPRIMARY); 410 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.COMPANY, 411 android.provider.Contacts.Organizations.COMPANY); 412 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.TYPE, 413 android.provider.Contacts.Organizations.TYPE); 414 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.LABEL, 415 android.provider.Contacts.Organizations.LABEL); 416 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.TITLE, 417 android.provider.Contacts.Organizations.TITLE); 418 419 sContactMethodProjectionMap = new HashMap<String, String>(peopleProjectionMap); 420 sContactMethodProjectionMap.put(ContactMethods._ID, ContactMethods._ID); 421 sContactMethodProjectionMap.put(ContactMethods.PERSON_ID, ContactMethods.PERSON_ID); 422 sContactMethodProjectionMap.put(ContactMethods.KIND, ContactMethods.KIND); 423 sContactMethodProjectionMap.put(ContactMethods.ISPRIMARY, ContactMethods.ISPRIMARY); 424 sContactMethodProjectionMap.put(ContactMethods.TYPE, ContactMethods.TYPE); 425 sContactMethodProjectionMap.put(ContactMethods.DATA, ContactMethods.DATA); 426 sContactMethodProjectionMap.put(ContactMethods.LABEL, ContactMethods.LABEL); 427 sContactMethodProjectionMap.put(ContactMethods.AUX_DATA, ContactMethods.AUX_DATA); 428 429 sPhoneProjectionMap = new HashMap<String, String>(peopleProjectionMap); 430 sPhoneProjectionMap.put(android.provider.Contacts.Phones._ID, 431 android.provider.Contacts.Phones._ID); 432 sPhoneProjectionMap.put(android.provider.Contacts.Phones.PERSON_ID, 433 android.provider.Contacts.Phones.PERSON_ID); 434 sPhoneProjectionMap.put(android.provider.Contacts.Phones.ISPRIMARY, 435 android.provider.Contacts.Phones.ISPRIMARY); 436 sPhoneProjectionMap.put(android.provider.Contacts.Phones.NUMBER, 437 android.provider.Contacts.Phones.NUMBER); 438 sPhoneProjectionMap.put(android.provider.Contacts.Phones.TYPE, 439 android.provider.Contacts.Phones.TYPE); 440 sPhoneProjectionMap.put(android.provider.Contacts.Phones.LABEL, 441 android.provider.Contacts.Phones.LABEL); 442 sPhoneProjectionMap.put(android.provider.Contacts.Phones.NUMBER_KEY, 443 android.provider.Contacts.Phones.NUMBER_KEY); 444 445 sExtensionProjectionMap = new HashMap<String, String>(); 446 sExtensionProjectionMap.put(android.provider.Contacts.Extensions._ID, 447 android.provider.Contacts.Extensions._ID); 448 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.PERSON_ID, 449 android.provider.Contacts.Extensions.PERSON_ID); 450 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.NAME, 451 android.provider.Contacts.Extensions.NAME); 452 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.VALUE, 453 android.provider.Contacts.Extensions.VALUE); 454 455 sGroupProjectionMap = new HashMap<String, String>(); 456 sGroupProjectionMap.put(android.provider.Contacts.Groups._ID, 457 android.provider.Contacts.Groups._ID); 458 sGroupProjectionMap.put(android.provider.Contacts.Groups.NAME, 459 android.provider.Contacts.Groups.NAME); 460 sGroupProjectionMap.put(android.provider.Contacts.Groups.NOTES, 461 android.provider.Contacts.Groups.NOTES); 462 sGroupProjectionMap.put(android.provider.Contacts.Groups.SYSTEM_ID, 463 android.provider.Contacts.Groups.SYSTEM_ID); 464 465 sGroupMembershipProjectionMap = new HashMap<String, String>(sGroupProjectionMap); 466 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership._ID, 467 android.provider.Contacts.GroupMembership._ID); 468 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership.PERSON_ID, 469 android.provider.Contacts.GroupMembership.PERSON_ID); 470 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership.GROUP_ID, 471 android.provider.Contacts.GroupMembership.GROUP_ID); 472 sGroupMembershipProjectionMap.put( 473 android.provider.Contacts.GroupMembership.GROUP_SYNC_ID, 474 android.provider.Contacts.GroupMembership.GROUP_SYNC_ID); 475 sGroupMembershipProjectionMap.put( 476 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT, 477 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT); 478 sGroupMembershipProjectionMap.put( 479 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT_TYPE, 480 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT_TYPE); 481 482 sPhotoProjectionMap = new HashMap<String, String>(); 483 sPhotoProjectionMap.put(android.provider.Contacts.Photos._ID, 484 android.provider.Contacts.Photos._ID); 485 sPhotoProjectionMap.put(android.provider.Contacts.Photos.PERSON_ID, 486 android.provider.Contacts.Photos.PERSON_ID); 487 sPhotoProjectionMap.put(android.provider.Contacts.Photos.DATA, 488 android.provider.Contacts.Photos.DATA); 489 sPhotoProjectionMap.put(android.provider.Contacts.Photos.LOCAL_VERSION, 490 android.provider.Contacts.Photos.LOCAL_VERSION); 491 sPhotoProjectionMap.put(android.provider.Contacts.Photos.DOWNLOAD_REQUIRED, 492 android.provider.Contacts.Photos.DOWNLOAD_REQUIRED); 493 sPhotoProjectionMap.put(android.provider.Contacts.Photos.EXISTS_ON_SERVER, 494 android.provider.Contacts.Photos.EXISTS_ON_SERVER); 495 sPhotoProjectionMap.put(android.provider.Contacts.Photos.SYNC_ERROR, 496 android.provider.Contacts.Photos.SYNC_ERROR); 497 } 498 499 private final Context mContext; 500 private final ContactsDatabaseHelper mDbHelper; 501 private final ContactsProvider2 mContactsProvider; 502 private final NameSplitter mPhoneticNameSplitter; 503 private final GlobalSearchSupport mGlobalSearchSupport; 504 505 private final SQLiteStatement mDataMimetypeQuery; 506 private final SQLiteStatement mDataRawContactIdQuery; 507 508 private final ContentValues mValues = new ContentValues(); 509 private final ContentValues mValues2 = new ContentValues(); 510 private final ContentValues mValues3 = new ContentValues(); 511 private boolean mDefaultAccountKnown; 512 private Account mAccount; 513 514 private final long mMimetypeEmail; 515 private final long mMimetypeIm; 516 private final long mMimetypePostal; 517 518 519 public LegacyApiSupport(Context context, ContactsDatabaseHelper contactsDatabaseHelper, 520 ContactsProvider2 contactsProvider, GlobalSearchSupport globalSearchSupport) { 521 mContext = context; 522 mContactsProvider = contactsProvider; 523 mDbHelper = contactsDatabaseHelper; 524 mGlobalSearchSupport = globalSearchSupport; 525 526 mPhoneticNameSplitter = new NameSplitter("", "", "", context 527 .getString(com.android.internal.R.string.common_name_conjunctions), Locale 528 .getDefault()); 529 530 SQLiteDatabase db = mDbHelper.getReadableDatabase(); 531 mDataMimetypeQuery = db.compileStatement( 532 "SELECT " + DataColumns.MIMETYPE_ID + 533 " FROM " + Tables.DATA + 534 " WHERE " + Data._ID + "=?"); 535 536 mDataRawContactIdQuery = db.compileStatement( 537 "SELECT " + Data.RAW_CONTACT_ID + 538 " FROM " + Tables.DATA + 539 " WHERE " + Data._ID + "=?"); 540 541 mMimetypeEmail = mDbHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE); 542 mMimetypeIm = mDbHelper.getMimeTypeId(Im.CONTENT_ITEM_TYPE); 543 mMimetypePostal = mDbHelper.getMimeTypeId(StructuredPostal.CONTENT_ITEM_TYPE); 544 } 545 546 private void ensureDefaultAccount() { 547 if (!mDefaultAccountKnown) { 548 mAccount = mContactsProvider.getDefaultAccount(); 549 mDefaultAccountKnown = true; 550 } 551 } 552 553 public static void createDatabase(SQLiteDatabase db) { 554 Log.i(TAG, "Bootstrapping database legacy support"); 555 createViews(db); 556 createSettingsTable(db); 557 } 558 559 public static void createViews(SQLiteDatabase db) { 560 561 String peopleColumns = "name." + StructuredName.DISPLAY_NAME 562 + " AS " + People.NAME + ", " + 563 Tables.RAW_CONTACTS + "." + RawContactsColumns.DISPLAY_NAME 564 + " AS " + People.DISPLAY_NAME + ", " + 565 PHONETIC_NAME_SQL 566 + " AS " + People.PHONETIC_NAME + " , " + 567 "note." + Note.NOTE 568 + " AS " + People.NOTES + ", " + 569 AccountsColumns.CONCRETE_ACCOUNT_NAME + ", " + 570 AccountsColumns.CONCRETE_ACCOUNT_TYPE + ", " + 571 Tables.RAW_CONTACTS + "." + RawContacts.TIMES_CONTACTED 572 + " AS " + People.TIMES_CONTACTED + ", " + 573 Tables.RAW_CONTACTS + "." + RawContacts.LAST_TIME_CONTACTED 574 + " AS " + People.LAST_TIME_CONTACTED + ", " + 575 Tables.RAW_CONTACTS + "." + RawContacts.CUSTOM_RINGTONE 576 + " AS " + People.CUSTOM_RINGTONE + ", " + 577 Tables.RAW_CONTACTS + "." + RawContacts.SEND_TO_VOICEMAIL 578 + " AS " + People.SEND_TO_VOICEMAIL + ", " + 579 Tables.RAW_CONTACTS + "." + RawContacts.STARRED 580 + " AS " + People.STARRED + ", " + 581 "organization." + Data._ID 582 + " AS " + People.PRIMARY_ORGANIZATION_ID + ", " + 583 "email." + Data._ID 584 + " AS " + People.PRIMARY_EMAIL_ID + ", " + 585 "phone." + Data._ID 586 + " AS " + People.PRIMARY_PHONE_ID + ", " + 587 "phone." + Phone.NUMBER 588 + " AS " + People.NUMBER + ", " + 589 "phone." + Phone.TYPE 590 + " AS " + People.TYPE + ", " + 591 "phone." + Phone.LABEL 592 + " AS " + People.LABEL + ", " + 593 "_PHONE_NUMBER_STRIPPED_REVERSED(phone." + Phone.NUMBER + ")" 594 + " AS " + People.NUMBER_KEY; 595 596 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.PEOPLE + ";"); 597 db.execSQL("CREATE VIEW " + LegacyTables.PEOPLE + " AS SELECT " + 598 RawContactsColumns.CONCRETE_ID 599 + " AS " + android.provider.Contacts.People._ID + ", " + 600 peopleColumns + 601 " FROM " + Tables.RAW_CONTACTS + PEOPLE_JOINS + 602 " WHERE " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0;"); 603 604 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.ORGANIZATIONS + ";"); 605 db.execSQL("CREATE VIEW " + LegacyTables.ORGANIZATIONS + " AS SELECT " + 606 DataColumns.CONCRETE_ID 607 + " AS " + android.provider.Contacts.Organizations._ID + ", " + 608 Data.RAW_CONTACT_ID 609 + " AS " + android.provider.Contacts.Organizations.PERSON_ID + ", " + 610 Data.IS_PRIMARY 611 + " AS " + android.provider.Contacts.Organizations.ISPRIMARY + ", " + 612 AccountsColumns.CONCRETE_ACCOUNT_NAME + ", " + 613 AccountsColumns.CONCRETE_ACCOUNT_TYPE + ", " + 614 Organization.COMPANY 615 + " AS " + android.provider.Contacts.Organizations.COMPANY + ", " + 616 Organization.TYPE 617 + " AS " + android.provider.Contacts.Organizations.TYPE + ", " + 618 Organization.LABEL 619 + " AS " + android.provider.Contacts.Organizations.LABEL + ", " + 620 Organization.TITLE 621 + " AS " + android.provider.Contacts.Organizations.TITLE + 622 " FROM " + Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS + 623 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 624 + Organization.CONTENT_ITEM_TYPE + "'" 625 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" + 626 ";"); 627 628 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.CONTACT_METHODS + ";"); 629 db.execSQL("CREATE VIEW " + LegacyTables.CONTACT_METHODS + " AS SELECT " + 630 DataColumns.CONCRETE_ID 631 + " AS " + ContactMethods._ID + ", " + 632 DataColumns.CONCRETE_RAW_CONTACT_ID 633 + " AS " + ContactMethods.PERSON_ID + ", " + 634 CONTACT_METHOD_KIND_SQL 635 + " AS " + ContactMethods.KIND + ", " + 636 DataColumns.CONCRETE_IS_PRIMARY 637 + " AS " + ContactMethods.ISPRIMARY + ", " + 638 Tables.DATA + "." + Email.TYPE 639 + " AS " + ContactMethods.TYPE + ", " + 640 CONTACT_METHOD_DATA_SQL 641 + " AS " + ContactMethods.DATA + ", " + 642 Tables.DATA + "." + Email.LABEL 643 + " AS " + ContactMethods.LABEL + ", " + 644 DataColumns.CONCRETE_DATA14 645 + " AS " + ContactMethods.AUX_DATA + ", " + 646 peopleColumns + 647 " FROM " + Tables.DATA + DATA_JOINS + 648 " WHERE " + ContactMethods.KIND + " IS NOT NULL" 649 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" + 650 ";"); 651 652 653 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.PHONES + ";"); 654 db.execSQL("CREATE VIEW " + LegacyTables.PHONES + " AS SELECT DISTINCT " + 655 DataColumns.CONCRETE_ID 656 + " AS " + android.provider.Contacts.Phones._ID + ", " + 657 DataColumns.CONCRETE_RAW_CONTACT_ID 658 + " AS " + android.provider.Contacts.Phones.PERSON_ID + ", " + 659 DataColumns.CONCRETE_IS_PRIMARY 660 + " AS " + android.provider.Contacts.Phones.ISPRIMARY + ", " + 661 Tables.DATA + "." + Phone.NUMBER 662 + " AS " + android.provider.Contacts.Phones.NUMBER + ", " + 663 Tables.DATA + "." + Phone.TYPE 664 + " AS " + android.provider.Contacts.Phones.TYPE + ", " + 665 Tables.DATA + "." + Phone.LABEL 666 + " AS " + android.provider.Contacts.Phones.LABEL + ", " + 667 "_PHONE_NUMBER_STRIPPED_REVERSED(" + Tables.DATA + "." + Phone.NUMBER + ")" 668 + " AS " + android.provider.Contacts.Phones.NUMBER_KEY + ", " + 669 peopleColumns + 670 " FROM " + Tables.DATA 671 + " JOIN " + Tables.PHONE_LOOKUP 672 + " ON (" + Tables.DATA + "._id = " 673 + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.DATA_ID + ")" 674 + DATA_JOINS + 675 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 676 + Phone.CONTENT_ITEM_TYPE + "'" 677 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" + 678 ";"); 679 680 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.EXTENSIONS + ";"); 681 db.execSQL("CREATE VIEW " + LegacyTables.EXTENSIONS + " AS SELECT " + 682 DataColumns.CONCRETE_ID 683 + " AS " + android.provider.Contacts.Extensions._ID + ", " + 684 DataColumns.CONCRETE_RAW_CONTACT_ID 685 + " AS " + android.provider.Contacts.Extensions.PERSON_ID + ", " + 686 AccountsColumns.CONCRETE_ACCOUNT_NAME + ", " + 687 AccountsColumns.CONCRETE_ACCOUNT_TYPE + ", " + 688 ExtensionsColumns.NAME 689 + " AS " + android.provider.Contacts.Extensions.NAME + ", " + 690 ExtensionsColumns.VALUE 691 + " AS " + android.provider.Contacts.Extensions.VALUE + 692 " FROM " + Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS + 693 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 694 + android.provider.Contacts.Extensions.CONTENT_ITEM_TYPE + "'" 695 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" + 696 ";"); 697 698 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.GROUPS + ";"); 699 db.execSQL("CREATE VIEW " + LegacyTables.GROUPS + " AS SELECT " + 700 GroupsColumns.CONCRETE_ID + " AS " + android.provider.Contacts.Groups._ID + ", " + 701 AccountsColumns.CONCRETE_ACCOUNT_NAME + ", " + 702 AccountsColumns.CONCRETE_ACCOUNT_TYPE + ", " + 703 Groups.TITLE + " AS " + android.provider.Contacts.Groups.NAME + ", " + 704 Groups.NOTES + " AS " + android.provider.Contacts.Groups.NOTES + " , " + 705 Groups.SYSTEM_ID + " AS " + android.provider.Contacts.Groups.SYSTEM_ID + 706 " FROM " + Tables.GROUPS + 707 " JOIN " + Tables.ACCOUNTS + " ON (" + 708 GroupsColumns.CONCRETE_ACCOUNT_ID + "=" + AccountsColumns.CONCRETE_ID + ")" + 709 ";"); 710 711 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.GROUP_MEMBERSHIP + ";"); 712 db.execSQL("CREATE VIEW " + LegacyTables.GROUP_MEMBERSHIP + " AS SELECT " + 713 DataColumns.CONCRETE_ID 714 + " AS " + android.provider.Contacts.GroupMembership._ID + ", " + 715 DataColumns.CONCRETE_RAW_CONTACT_ID 716 + " AS " + android.provider.Contacts.GroupMembership.PERSON_ID + ", " + 717 AccountsColumns.CONCRETE_ACCOUNT_NAME + ", " + 718 AccountsColumns.CONCRETE_ACCOUNT_TYPE + ", " + 719 GroupMembership.GROUP_ROW_ID 720 + " AS " + android.provider.Contacts.GroupMembership.GROUP_ID + ", " + 721 Groups.TITLE 722 + " AS " + android.provider.Contacts.GroupMembership.NAME + ", " + 723 Groups.NOTES 724 + " AS " + android.provider.Contacts.GroupMembership.NOTES + ", " + 725 Groups.SYSTEM_ID 726 + " AS " + android.provider.Contacts.GroupMembership.SYSTEM_ID + ", " + 727 GroupsColumns.CONCRETE_SOURCE_ID 728 + " AS " 729 + android.provider.Contacts.GroupMembership.GROUP_SYNC_ID + ", " + 730 AccountsColumns.CONCRETE_ACCOUNT_NAME 731 + " AS " 732 + android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT + ", " + 733 AccountsColumns.CONCRETE_ACCOUNT_TYPE 734 + " AS " 735 + android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT_TYPE + 736 " FROM " + Tables.DATA_JOIN_PACKAGES_MIMETYPES_RAW_CONTACTS_GROUPS + 737 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 738 + GroupMembership.CONTENT_ITEM_TYPE + "'" 739 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" + 740 ";"); 741 742 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.PHOTOS + ";"); 743 db.execSQL("CREATE VIEW " + LegacyTables.PHOTOS + " AS SELECT " + 744 DataColumns.CONCRETE_ID 745 + " AS " + android.provider.Contacts.Photos._ID + ", " + 746 DataColumns.CONCRETE_RAW_CONTACT_ID 747 + " AS " + android.provider.Contacts.Photos.PERSON_ID + ", " + 748 AccountsColumns.CONCRETE_ACCOUNT_NAME + ", " + 749 AccountsColumns.CONCRETE_ACCOUNT_TYPE + ", " + 750 Tables.DATA + "." + Photo.PHOTO 751 + " AS " + android.provider.Contacts.Photos.DATA + ", " + 752 "legacy_photo." + LegacyPhotoData.EXISTS_ON_SERVER 753 + " AS " + android.provider.Contacts.Photos.EXISTS_ON_SERVER + ", " + 754 "legacy_photo." + LegacyPhotoData.DOWNLOAD_REQUIRED 755 + " AS " + android.provider.Contacts.Photos.DOWNLOAD_REQUIRED + ", " + 756 "legacy_photo." + LegacyPhotoData.LOCAL_VERSION 757 + " AS " + android.provider.Contacts.Photos.LOCAL_VERSION + ", " + 758 "legacy_photo." + LegacyPhotoData.SYNC_ERROR 759 + " AS " + android.provider.Contacts.Photos.SYNC_ERROR + 760 " FROM " + Tables.DATA + DATA_JOINS + LEGACY_PHOTO_JOIN + 761 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 762 + Photo.CONTENT_ITEM_TYPE + "'" 763 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" + 764 ";"); 765 766 } 767 768 public static void createSettingsTable(SQLiteDatabase db) { 769 db.execSQL("DROP TABLE IF EXISTS " + LegacyTables.SETTINGS + ";"); 770 db.execSQL("CREATE TABLE " + LegacyTables.SETTINGS + " (" + 771 android.provider.Contacts.Settings._ID + " INTEGER PRIMARY KEY," + 772 android.provider.Contacts.Settings._SYNC_ACCOUNT + " TEXT," + 773 android.provider.Contacts.Settings._SYNC_ACCOUNT_TYPE + " TEXT," + 774 android.provider.Contacts.Settings.KEY + " STRING NOT NULL," + 775 android.provider.Contacts.Settings.VALUE + " STRING " + 776 ");"); 777 } 778 779 public Uri insert(Uri uri, ContentValues values) { 780 ensureDefaultAccount(); 781 final int match = sUriMatcher.match(uri); 782 long id = 0; 783 switch (match) { 784 case PEOPLE: 785 id = insertPeople(values); 786 break; 787 788 case ORGANIZATIONS: 789 id = insertOrganization(values); 790 break; 791 792 case PEOPLE_CONTACTMETHODS: { 793 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 794 id = insertContactMethod(rawContactId, values); 795 break; 796 } 797 798 case CONTACTMETHODS: { 799 long rawContactId = getRequiredValue(values, ContactMethods.PERSON_ID); 800 id = insertContactMethod(rawContactId, values); 801 break; 802 } 803 804 case PHONES: { 805 long rawContactId = getRequiredValue(values, 806 android.provider.Contacts.Phones.PERSON_ID); 807 id = insertPhone(rawContactId, values); 808 break; 809 } 810 811 case PEOPLE_PHONES: { 812 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 813 id = insertPhone(rawContactId, values); 814 break; 815 } 816 817 case EXTENSIONS: { 818 long rawContactId = getRequiredValue(values, 819 android.provider.Contacts.Extensions.PERSON_ID); 820 id = insertExtension(rawContactId, values); 821 break; 822 } 823 824 case GROUPS: 825 id = insertGroup(values); 826 break; 827 828 case GROUPMEMBERSHIP: { 829 long rawContactId = getRequiredValue(values, 830 android.provider.Contacts.GroupMembership.PERSON_ID); 831 long groupId = getRequiredValue(values, 832 android.provider.Contacts.GroupMembership.GROUP_ID); 833 id = insertGroupMembership(rawContactId, groupId); 834 break; 835 } 836 837 default: 838 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 839 } 840 841 if (id < 0) { 842 return null; 843 } 844 845 final Uri result = ContentUris.withAppendedId(uri, id); 846 onChange(result); 847 return result; 848 } 849 850 private long getRequiredValue(ContentValues values, String column) { 851 final Long value = values.getAsLong(column); 852 if (value == null) { 853 throw new RuntimeException("Required value: " + column); 854 } 855 856 return value; 857 } 858 859 private long insertPeople(ContentValues values) { 860 parsePeopleValues(values); 861 862 Uri contactUri = mContactsProvider.insertInTransaction(RawContacts.CONTENT_URI, mValues); 863 long rawContactId = ContentUris.parseId(contactUri); 864 865 if (mValues2.size() != 0) { 866 mValues2.put(Data.RAW_CONTACT_ID, rawContactId); 867 mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues2); 868 } 869 if (mValues3.size() != 0) { 870 mValues3.put(Data.RAW_CONTACT_ID, rawContactId); 871 mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues3); 872 } 873 874 return rawContactId; 875 } 876 877 private long insertOrganization(ContentValues values) { 878 parseOrganizationValues(values); 879 ContactsDatabaseHelper.copyLongValue(mValues, Data.RAW_CONTACT_ID, 880 values, android.provider.Contacts.Organizations.PERSON_ID); 881 882 Uri uri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 883 884 return ContentUris.parseId(uri); 885 } 886 887 private long insertPhone(long rawContactId, ContentValues values) { 888 parsePhoneValues(values); 889 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 890 891 Uri uri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 892 893 return ContentUris.parseId(uri); 894 } 895 896 private long insertContactMethod(long rawContactId, ContentValues values) { 897 Integer kind = values.getAsInteger(ContactMethods.KIND); 898 if (kind == null) { 899 throw new RuntimeException("Required value: " + ContactMethods.KIND); 900 } 901 902 parseContactMethodValues(kind, values); 903 904 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 905 Uri uri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 906 return ContentUris.parseId(uri); 907 } 908 909 private long insertExtension(long rawContactId, ContentValues values) { 910 mValues.clear(); 911 912 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 913 mValues.put(Data.MIMETYPE, android.provider.Contacts.Extensions.CONTENT_ITEM_TYPE); 914 915 parseExtensionValues(values); 916 917 Uri uri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 918 return ContentUris.parseId(uri); 919 } 920 921 private long insertGroup(ContentValues values) { 922 parseGroupValues(values); 923 924 if (mAccount != null) { 925 mValues.put(Groups.ACCOUNT_NAME, mAccount.name); 926 mValues.put(Groups.ACCOUNT_TYPE, mAccount.type); 927 } 928 929 Uri uri = mContactsProvider.insertInTransaction(Groups.CONTENT_URI, mValues); 930 return ContentUris.parseId(uri); 931 } 932 933 private long insertGroupMembership(long rawContactId, long groupId) { 934 mValues.clear(); 935 936 mValues.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE); 937 mValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 938 mValues.put(GroupMembership.GROUP_ROW_ID, groupId); 939 940 Uri uri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 941 return ContentUris.parseId(uri); 942 } 943 944 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 945 ensureDefaultAccount(); 946 947 int match = sUriMatcher.match(uri); 948 int count = 0; 949 switch(match) { 950 case PEOPLE_UPDATE_CONTACT_TIME: { 951 count = updateContactTime(uri, values); 952 break; 953 } 954 955 case PEOPLE_PHOTO: { 956 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 957 return updatePhoto(rawContactId, values); 958 } 959 960 case SETTINGS: { 961 return updateSettings(values); 962 } 963 964 case GROUPMEMBERSHIP: 965 case GROUPMEMBERSHIP_ID: 966 case -1: { 967 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 968 } 969 970 default: { 971 count = updateAll(uri, match, values, selection, selectionArgs); 972 } 973 } 974 975 if (count > 0) { 976 mContext.getContentResolver().notifyChange(uri, null); 977 } 978 979 return count; 980 } 981 982 private int updateAll(Uri uri, final int match, ContentValues values, String selection, 983 String[] selectionArgs) { 984 Cursor c = query(uri, IdQuery.COLUMNS, selection, selectionArgs, null, null); 985 if (c == null) { 986 return 0; 987 } 988 989 int count = 0; 990 try { 991 while (c.moveToNext()) { 992 long id = c.getLong(IdQuery._ID); 993 count += update(match, id, values); 994 } 995 } finally { 996 c.close(); 997 } 998 999 return count; 1000 } 1001 1002 public int update(int match, long id, ContentValues values) { 1003 int count = 0; 1004 switch(match) { 1005 case PEOPLE: 1006 case PEOPLE_ID: { 1007 count = updatePeople(id, values); 1008 break; 1009 } 1010 1011 case ORGANIZATIONS: 1012 case ORGANIZATIONS_ID: { 1013 count = updateOrganizations(id, values); 1014 break; 1015 } 1016 1017 case PHONES: 1018 case PHONES_ID: { 1019 count = updatePhones(id, values); 1020 break; 1021 } 1022 1023 case CONTACTMETHODS: 1024 case CONTACTMETHODS_ID: { 1025 count = updateContactMethods(id, values); 1026 break; 1027 } 1028 1029 case EXTENSIONS: 1030 case EXTENSIONS_ID: { 1031 count = updateExtensions(id, values); 1032 break; 1033 } 1034 1035 case GROUPS: 1036 case GROUPS_ID: { 1037 count = updateGroups(id, values); 1038 break; 1039 } 1040 1041 case PHOTOS: 1042 case PHOTOS_ID: 1043 count = updatePhotoByDataId(id, values); 1044 break; 1045 } 1046 1047 return count; 1048 } 1049 1050 private int updatePeople(long rawContactId, ContentValues values) { 1051 parsePeopleValues(values); 1052 1053 int count = mContactsProvider.updateInTransaction(RawContacts.CONTENT_URI, 1054 mValues, RawContacts._ID + "=" + rawContactId, null); 1055 1056 if (count == 0) { 1057 return 0; 1058 } 1059 1060 if (mValues2.size() != 0) { 1061 Uri dataUri = findFirstDataRow(rawContactId, StructuredName.CONTENT_ITEM_TYPE); 1062 if (dataUri != null) { 1063 mContactsProvider.updateInTransaction(dataUri, mValues2, null, null); 1064 } else { 1065 mValues2.put(Data.RAW_CONTACT_ID, rawContactId); 1066 mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues2); 1067 } 1068 } 1069 1070 if (mValues3.size() != 0) { 1071 Uri dataUri = findFirstDataRow(rawContactId, Note.CONTENT_ITEM_TYPE); 1072 if (dataUri != null) { 1073 mContactsProvider.updateInTransaction(dataUri, mValues3, null, null); 1074 } else { 1075 mValues3.put(Data.RAW_CONTACT_ID, rawContactId); 1076 mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues3); 1077 } 1078 } 1079 1080 if (values.containsKey(People.LAST_TIME_CONTACTED) && 1081 !values.containsKey(People.TIMES_CONTACTED)) { 1082 updateContactTime(rawContactId, values); 1083 } 1084 1085 return count; 1086 } 1087 1088 private int updateOrganizations(long dataId, ContentValues values) { 1089 parseOrganizationValues(values); 1090 1091 return mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1092 Data._ID + "=" + dataId, null); 1093 } 1094 1095 private int updatePhones(long dataId, ContentValues values) { 1096 parsePhoneValues(values); 1097 1098 return mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1099 Data._ID + "=" + dataId, null); 1100 } 1101 1102 private int updateContactMethods(long dataId, ContentValues values) { 1103 int kind; 1104 1105 mDataMimetypeQuery.bindLong(1, dataId); 1106 long mimetype_id; 1107 try { 1108 mimetype_id = mDataMimetypeQuery.simpleQueryForLong(); 1109 } catch (SQLiteDoneException e) { 1110 // Data row not found 1111 return 0; 1112 } 1113 1114 if (mimetype_id == mMimetypeEmail) { 1115 kind = android.provider.Contacts.KIND_EMAIL; 1116 } else if (mimetype_id == mMimetypeIm) { 1117 kind = android.provider.Contacts.KIND_IM; 1118 } else if (mimetype_id == mMimetypePostal) { 1119 kind = android.provider.Contacts.KIND_POSTAL; 1120 } else { 1121 1122 // Non-legacy kind: return "Not found" 1123 return 0; 1124 } 1125 1126 parseContactMethodValues(kind, values); 1127 1128 return mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1129 Data._ID + "=" + dataId, null); 1130 } 1131 1132 private int updateExtensions(long dataId, ContentValues values) { 1133 parseExtensionValues(values); 1134 1135 return mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1136 Data._ID + "=" + dataId, null); 1137 } 1138 1139 private int updateGroups(long groupId, ContentValues values) { 1140 parseGroupValues(values); 1141 1142 return mContactsProvider.updateInTransaction(Groups.CONTENT_URI, mValues, 1143 Groups._ID + "=" + groupId, null); 1144 } 1145 1146 private int updateContactTime(Uri uri, ContentValues values) { 1147 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 1148 updateContactTime(rawContactId, values); 1149 return 1; 1150 } 1151 1152 private void updateContactTime(long rawContactId, ContentValues values) { 1153 final Long storedTimeContacted = values.getAsLong(People.LAST_TIME_CONTACTED); 1154 final long lastTimeContacted = storedTimeContacted != null ? 1155 storedTimeContacted : System.currentTimeMillis(); 1156 1157 // TODO check sanctions 1158 long contactId = mDbHelper.getContactId(rawContactId); 1159 SQLiteDatabase mDb = mDbHelper.getWritableDatabase(); 1160 mSelectionArgs2[0] = String.valueOf(lastTimeContacted); 1161 if (contactId != 0) { 1162 mSelectionArgs2[1] = String.valueOf(contactId); 1163 mDb.execSQL(CONTACTS_UPDATE_LASTTIMECONTACTED, mSelectionArgs2); 1164 // increment times_contacted column 1165 mSelectionArgs1[0] = String.valueOf(contactId); 1166 mDb.execSQL(ContactsProvider2.UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 1167 } 1168 mSelectionArgs2[1] = String.valueOf(rawContactId); 1169 mDb.execSQL(RAWCONTACTS_UPDATE_LASTTIMECONTACTED, mSelectionArgs2); 1170 // increment times_contacted column 1171 mSelectionArgs1[0] = String.valueOf(contactId); 1172 mDb.execSQL(ContactsProvider2.UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 1173 } 1174 1175 private int updatePhoto(long rawContactId, ContentValues values) { 1176 1177 // TODO check sanctions 1178 1179 int count; 1180 1181 long dataId = findFirstDataId(rawContactId, Photo.CONTENT_ITEM_TYPE); 1182 1183 mValues.clear(); 1184 byte[] bytes = values.getAsByteArray(android.provider.Contacts.Photos.DATA); 1185 mValues.put(Photo.PHOTO, bytes); 1186 1187 if (dataId == -1) { 1188 mValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 1189 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 1190 Uri dataUri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 1191 dataId = ContentUris.parseId(dataUri); 1192 count = 1; 1193 } else { 1194 Uri dataUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId); 1195 count = mContactsProvider.updateInTransaction(dataUri, mValues, null, null); 1196 } 1197 1198 updateLegacyPhotoData(rawContactId, dataId, values); 1199 1200 return count; 1201 } 1202 1203 private int updatePhotoByDataId(long dataId, ContentValues values) { 1204 1205 mDataRawContactIdQuery.bindLong(1, dataId); 1206 long rawContactId; 1207 1208 try { 1209 rawContactId = mDataRawContactIdQuery.simpleQueryForLong(); 1210 } catch (SQLiteDoneException e) { 1211 // Data row not found 1212 return 0; 1213 } 1214 1215 if (values.containsKey(android.provider.Contacts.Photos.DATA)) { 1216 byte[] bytes = values.getAsByteArray(android.provider.Contacts.Photos.DATA); 1217 mValues.clear(); 1218 mValues.put(Photo.PHOTO, bytes); 1219 mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1220 Data._ID + "=" + dataId, null); 1221 } 1222 1223 updateLegacyPhotoData(rawContactId, dataId, values); 1224 1225 return 1; 1226 } 1227 1228 private void updateLegacyPhotoData(long rawContactId, long dataId, ContentValues values) { 1229 mValues.clear(); 1230 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.LOCAL_VERSION, 1231 values, android.provider.Contacts.Photos.LOCAL_VERSION); 1232 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.DOWNLOAD_REQUIRED, 1233 values, android.provider.Contacts.Photos.DOWNLOAD_REQUIRED); 1234 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.EXISTS_ON_SERVER, 1235 values, android.provider.Contacts.Photos.EXISTS_ON_SERVER); 1236 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.SYNC_ERROR, 1237 values, android.provider.Contacts.Photos.SYNC_ERROR); 1238 1239 int updated = mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1240 Data.MIMETYPE + "='" + LegacyPhotoData.CONTENT_ITEM_TYPE + "'" 1241 + " AND " + Data.RAW_CONTACT_ID + "=" + rawContactId 1242 + " AND " + LegacyPhotoData.PHOTO_DATA_ID + "=" + dataId, null); 1243 if (updated == 0) { 1244 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 1245 mValues.put(Data.MIMETYPE, LegacyPhotoData.CONTENT_ITEM_TYPE); 1246 mValues.put(LegacyPhotoData.PHOTO_DATA_ID, dataId); 1247 mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 1248 } 1249 } 1250 1251 private int updateSettings(ContentValues values) { 1252 SQLiteDatabase db = mDbHelper.getWritableDatabase(); 1253 String accountName = values.getAsString(android.provider.Contacts.Settings._SYNC_ACCOUNT); 1254 String accountType = 1255 values.getAsString(android.provider.Contacts.Settings._SYNC_ACCOUNT_TYPE); 1256 String key = values.getAsString(android.provider.Contacts.Settings.KEY); 1257 if (key == null) { 1258 throw new IllegalArgumentException("you must specify the key when updating settings"); 1259 } 1260 updateSetting(db, accountName, accountType, values); 1261 if (key.equals(android.provider.Contacts.Settings.SYNC_EVERYTHING)) { 1262 mValues.clear(); 1263 mValues.put(Settings.SHOULD_SYNC, 1264 values.getAsInteger(android.provider.Contacts.Settings.VALUE)); 1265 String selection; 1266 String[] selectionArgs; 1267 if (accountName != null && accountType != null) { 1268 1269 selectionArgs = new String[]{accountName, accountType}; 1270 selection = Settings.ACCOUNT_NAME + "=?" 1271 + " AND " + Settings.ACCOUNT_TYPE + "=?" 1272 + " AND " + Settings.DATA_SET + " IS NULL"; 1273 } else { 1274 selectionArgs = null; 1275 selection = Settings.ACCOUNT_NAME + " IS NULL" 1276 + " AND " + Settings.ACCOUNT_TYPE + " IS NULL" 1277 + " AND " + Settings.DATA_SET + " IS NULL"; 1278 } 1279 int count = mContactsProvider.updateInTransaction(Settings.CONTENT_URI, mValues, 1280 selection, selectionArgs); 1281 if (count == 0) { 1282 mValues.put(Settings.ACCOUNT_NAME, accountName); 1283 mValues.put(Settings.ACCOUNT_TYPE, accountType); 1284 mContactsProvider.insertInTransaction(Settings.CONTENT_URI, mValues); 1285 } 1286 } 1287 return 1; 1288 } 1289 1290 private void updateSetting(SQLiteDatabase db, String accountName, String accountType, 1291 ContentValues values) { 1292 final String key = values.getAsString(android.provider.Contacts.Settings.KEY); 1293 if (accountName == null || accountType == null) { 1294 db.delete(LegacyTables.SETTINGS, "_sync_account IS NULL AND key=?", new String[]{key}); 1295 } else { 1296 db.delete(LegacyTables.SETTINGS, "_sync_account=? AND _sync_account_type=? AND key=?", 1297 new String[]{accountName, accountType, key}); 1298 } 1299 long rowId = db.insert(LegacyTables.SETTINGS, 1300 android.provider.Contacts.Settings.KEY, values); 1301 if (rowId < 0) { 1302 throw new SQLException("error updating settings with " + values); 1303 } 1304 } 1305 1306 private interface SettingsMatchQuery { 1307 String SQL = 1308 "SELECT " 1309 + ContactsContract.Settings.ACCOUNT_NAME + "," 1310 + ContactsContract.Settings.ACCOUNT_TYPE + "," 1311 + ContactsContract.Settings.SHOULD_SYNC + 1312 " FROM " + Tables.SETTINGS + " LEFT OUTER JOIN " + LegacyTables.SETTINGS + 1313 " ON (" + ContactsContract.Settings.ACCOUNT_NAME + "=" 1314 + android.provider.Contacts.Settings._SYNC_ACCOUNT + 1315 " AND " + ContactsContract.Settings.ACCOUNT_TYPE + "=" 1316 + android.provider.Contacts.Settings._SYNC_ACCOUNT_TYPE + 1317 " AND " + ContactsContract.Settings.DATA_SET + " IS NULL" + 1318 " AND " + android.provider.Contacts.Settings.KEY + "='" 1319 + android.provider.Contacts.Settings.SYNC_EVERYTHING + "'" + 1320 ")" + 1321 " WHERE " + ContactsContract.Settings.SHOULD_SYNC + "<>" 1322 + android.provider.Contacts.Settings.VALUE; 1323 1324 int ACCOUNT_NAME = 0; 1325 int ACCOUNT_TYPE = 1; 1326 int SHOULD_SYNC = 2; 1327 } 1328 1329 /** 1330 * Brings legacy settings table in sync with the new settings. 1331 */ 1332 public void copySettingsToLegacySettings() { 1333 SQLiteDatabase db = mDbHelper.getWritableDatabase(); 1334 Cursor cursor = db.rawQuery(SettingsMatchQuery.SQL, null); 1335 try { 1336 while(cursor.moveToNext()) { 1337 String accountName = cursor.getString(SettingsMatchQuery.ACCOUNT_NAME); 1338 String accountType = cursor.getString(SettingsMatchQuery.ACCOUNT_TYPE); 1339 String value = cursor.getString(SettingsMatchQuery.SHOULD_SYNC); 1340 mValues.clear(); 1341 mValues.put(android.provider.Contacts.Settings._SYNC_ACCOUNT, accountName); 1342 mValues.put(android.provider.Contacts.Settings._SYNC_ACCOUNT_TYPE, accountType); 1343 mValues.put(android.provider.Contacts.Settings.KEY, 1344 android.provider.Contacts.Settings.SYNC_EVERYTHING); 1345 mValues.put(android.provider.Contacts.Settings.VALUE, value); 1346 updateSetting(db, accountName, accountType, mValues); 1347 } 1348 } finally { 1349 cursor.close(); 1350 } 1351 } 1352 1353 private void parsePeopleValues(ContentValues values) { 1354 mValues.clear(); 1355 mValues2.clear(); 1356 mValues3.clear(); 1357 1358 ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 1359 values, People.CUSTOM_RINGTONE); 1360 ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 1361 values, People.SEND_TO_VOICEMAIL); 1362 ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 1363 values, People.LAST_TIME_CONTACTED); 1364 ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 1365 values, People.TIMES_CONTACTED); 1366 ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 1367 values, People.STARRED); 1368 if (mAccount != null) { 1369 mValues.put(RawContacts.ACCOUNT_NAME, mAccount.name); 1370 mValues.put(RawContacts.ACCOUNT_TYPE, mAccount.type); 1371 } 1372 1373 if (values.containsKey(People.NAME) || values.containsKey(People.PHONETIC_NAME)) { 1374 mValues2.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 1375 ContactsDatabaseHelper.copyStringValue(mValues2, StructuredName.DISPLAY_NAME, 1376 values, People.NAME); 1377 if (values.containsKey(People.PHONETIC_NAME)) { 1378 String phoneticName = values.getAsString(People.PHONETIC_NAME); 1379 NameSplitter.Name parsedName = new NameSplitter.Name(); 1380 mPhoneticNameSplitter.split(parsedName, phoneticName); 1381 mValues2.put(StructuredName.PHONETIC_GIVEN_NAME, parsedName.getGivenNames()); 1382 mValues2.put(StructuredName.PHONETIC_MIDDLE_NAME, parsedName.getMiddleName()); 1383 mValues2.put(StructuredName.PHONETIC_FAMILY_NAME, parsedName.getFamilyName()); 1384 } 1385 } 1386 1387 if (values.containsKey(People.NOTES)) { 1388 mValues3.put(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE); 1389 ContactsDatabaseHelper.copyStringValue(mValues3, Note.NOTE, values, People.NOTES); 1390 } 1391 } 1392 1393 private void parseOrganizationValues(ContentValues values) { 1394 mValues.clear(); 1395 1396 mValues.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE); 1397 1398 ContactsDatabaseHelper.copyLongValue(mValues, Data.IS_PRIMARY, 1399 values, android.provider.Contacts.Organizations.ISPRIMARY); 1400 1401 ContactsDatabaseHelper.copyStringValue(mValues, Organization.COMPANY, 1402 values, android.provider.Contacts.Organizations.COMPANY); 1403 1404 // TYPE values happen to remain the same between V1 and V2 - can just copy the value 1405 ContactsDatabaseHelper.copyLongValue(mValues, Organization.TYPE, 1406 values, android.provider.Contacts.Organizations.TYPE); 1407 1408 ContactsDatabaseHelper.copyStringValue(mValues, Organization.LABEL, 1409 values, android.provider.Contacts.Organizations.LABEL); 1410 ContactsDatabaseHelper.copyStringValue(mValues, Organization.TITLE, 1411 values, android.provider.Contacts.Organizations.TITLE); 1412 } 1413 1414 private void parsePhoneValues(ContentValues values) { 1415 mValues.clear(); 1416 1417 mValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1418 1419 ContactsDatabaseHelper.copyLongValue(mValues, Data.IS_PRIMARY, 1420 values, android.provider.Contacts.Phones.ISPRIMARY); 1421 1422 ContactsDatabaseHelper.copyStringValue(mValues, Phone.NUMBER, 1423 values, android.provider.Contacts.Phones.NUMBER); 1424 1425 // TYPE values happen to remain the same between V1 and V2 - can just copy the value 1426 ContactsDatabaseHelper.copyLongValue(mValues, Phone.TYPE, 1427 values, android.provider.Contacts.Phones.TYPE); 1428 1429 ContactsDatabaseHelper.copyStringValue(mValues, Phone.LABEL, 1430 values, android.provider.Contacts.Phones.LABEL); 1431 } 1432 1433 private void parseContactMethodValues(int kind, ContentValues values) { 1434 mValues.clear(); 1435 1436 ContactsDatabaseHelper.copyLongValue(mValues, Data.IS_PRIMARY, values, 1437 ContactMethods.ISPRIMARY); 1438 1439 switch (kind) { 1440 case android.provider.Contacts.KIND_EMAIL: { 1441 copyCommonFields(values, Email.CONTENT_ITEM_TYPE, Email.TYPE, Email.LABEL, 1442 Data.DATA14); 1443 ContactsDatabaseHelper.copyStringValue(mValues, Email.DATA, values, 1444 ContactMethods.DATA); 1445 break; 1446 } 1447 1448 case android.provider.Contacts.KIND_IM: { 1449 String protocol = values.getAsString(ContactMethods.DATA); 1450 if (protocol.startsWith("pre:")) { 1451 mValues.put(Im.PROTOCOL, Integer.parseInt(protocol.substring(4))); 1452 } else if (protocol.startsWith("custom:")) { 1453 mValues.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM); 1454 mValues.put(Im.CUSTOM_PROTOCOL, protocol.substring(7)); 1455 } 1456 1457 copyCommonFields(values, Im.CONTENT_ITEM_TYPE, Im.TYPE, Im.LABEL, Data.DATA14); 1458 break; 1459 } 1460 1461 case android.provider.Contacts.KIND_POSTAL: { 1462 copyCommonFields(values, StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, 1463 StructuredPostal.LABEL, Data.DATA14); 1464 ContactsDatabaseHelper.copyStringValue(mValues, StructuredPostal.FORMATTED_ADDRESS, 1465 values, ContactMethods.DATA); 1466 break; 1467 } 1468 } 1469 } 1470 1471 private void copyCommonFields(ContentValues values, String mimeType, String typeColumn, 1472 String labelColumn, String auxDataColumn) { 1473 mValues.put(Data.MIMETYPE, mimeType); 1474 ContactsDatabaseHelper.copyLongValue(mValues, typeColumn, values, 1475 ContactMethods.TYPE); 1476 ContactsDatabaseHelper.copyStringValue(mValues, labelColumn, values, 1477 ContactMethods.LABEL); 1478 ContactsDatabaseHelper.copyStringValue(mValues, auxDataColumn, values, 1479 ContactMethods.AUX_DATA); 1480 } 1481 1482 private void parseGroupValues(ContentValues values) { 1483 mValues.clear(); 1484 1485 ContactsDatabaseHelper.copyStringValue(mValues, Groups.TITLE, 1486 values, android.provider.Contacts.Groups.NAME); 1487 ContactsDatabaseHelper.copyStringValue(mValues, Groups.NOTES, 1488 values, android.provider.Contacts.Groups.NOTES); 1489 ContactsDatabaseHelper.copyStringValue(mValues, Groups.SYSTEM_ID, 1490 values, android.provider.Contacts.Groups.SYSTEM_ID); 1491 } 1492 1493 private void parseExtensionValues(ContentValues values) { 1494 ContactsDatabaseHelper.copyStringValue(mValues, ExtensionsColumns.NAME, 1495 values, android.provider.Contacts.People.Extensions.NAME); 1496 ContactsDatabaseHelper.copyStringValue(mValues, ExtensionsColumns.VALUE, 1497 values, android.provider.Contacts.People.Extensions.VALUE); 1498 } 1499 1500 private Uri findFirstDataRow(long rawContactId, String contentItemType) { 1501 long dataId = findFirstDataId(rawContactId, contentItemType); 1502 if (dataId == -1) { 1503 return null; 1504 } 1505 1506 return ContentUris.withAppendedId(Data.CONTENT_URI, dataId); 1507 } 1508 1509 private long findFirstDataId(long rawContactId, String mimeType) { 1510 long dataId = -1; 1511 Cursor c = mContactsProvider.query(Data.CONTENT_URI, IdQuery.COLUMNS, 1512 Data.RAW_CONTACT_ID + "=" + rawContactId + " AND " 1513 + Data.MIMETYPE + "='" + mimeType + "'", 1514 null, null); 1515 try { 1516 if (c.moveToFirst()) { 1517 dataId = c.getLong(IdQuery._ID); 1518 } 1519 } finally { 1520 c.close(); 1521 } 1522 return dataId; 1523 } 1524 1525 1526 public int delete(Uri uri, String selection, String[] selectionArgs) { 1527 final int match = sUriMatcher.match(uri); 1528 if (match == -1 || match == SETTINGS) { 1529 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 1530 } 1531 1532 Cursor c = query(uri, IdQuery.COLUMNS, selection, selectionArgs, null, null); 1533 if (c == null) { 1534 return 0; 1535 } 1536 1537 int count = 0; 1538 try { 1539 while (c.moveToNext()) { 1540 long id = c.getLong(IdQuery._ID); 1541 count += delete(uri, match, id); 1542 } 1543 } finally { 1544 c.close(); 1545 } 1546 1547 return count; 1548 } 1549 1550 public int delete(Uri uri, int match, long id) { 1551 int count = 0; 1552 switch (match) { 1553 case PEOPLE: 1554 case PEOPLE_ID: 1555 count = mContactsProvider.deleteRawContact(id, mDbHelper.getContactId(id), false); 1556 break; 1557 1558 case PEOPLE_PHOTO: 1559 mValues.clear(); 1560 mValues.putNull(android.provider.Contacts.Photos.DATA); 1561 updatePhoto(id, mValues); 1562 break; 1563 1564 case ORGANIZATIONS: 1565 case ORGANIZATIONS_ID: 1566 count = mContactsProvider.deleteData(id, ORGANIZATION_MIME_TYPES); 1567 break; 1568 1569 case CONTACTMETHODS: 1570 case CONTACTMETHODS_ID: 1571 count = mContactsProvider.deleteData(id, CONTACT_METHOD_MIME_TYPES); 1572 break; 1573 1574 case PHONES: 1575 case PHONES_ID: 1576 count = mContactsProvider.deleteData(id, PHONE_MIME_TYPES); 1577 break; 1578 1579 case EXTENSIONS: 1580 case EXTENSIONS_ID: 1581 count = mContactsProvider.deleteData(id, EXTENSION_MIME_TYPES); 1582 break; 1583 1584 case PHOTOS: 1585 case PHOTOS_ID: 1586 count = mContactsProvider.deleteData(id, PHOTO_MIME_TYPES); 1587 break; 1588 1589 case GROUPMEMBERSHIP: 1590 case GROUPMEMBERSHIP_ID: 1591 count = mContactsProvider.deleteData(id, GROUP_MEMBERSHIP_MIME_TYPES); 1592 break; 1593 1594 case GROUPS: 1595 case GROUPS_ID: 1596 count = mContactsProvider.deleteGroup(uri, id, false); 1597 break; 1598 1599 default: 1600 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 1601 } 1602 1603 return count; 1604 } 1605 1606 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 1607 String sortOrder, String limit) { 1608 ensureDefaultAccount(); 1609 1610 final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 1611 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 1612 String groupBy = null; 1613 1614 final int match = sUriMatcher.match(uri); 1615 switch (match) { 1616 case PEOPLE: { 1617 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1618 qb.setProjectionMap(sPeopleProjectionMap); 1619 applyRawContactsAccount(qb); 1620 break; 1621 } 1622 1623 case PEOPLE_ID: 1624 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1625 qb.setProjectionMap(sPeopleProjectionMap); 1626 applyRawContactsAccount(qb); 1627 qb.appendWhere(" AND " + People._ID + "="); 1628 qb.appendWhere(uri.getPathSegments().get(1)); 1629 break; 1630 1631 case PEOPLE_FILTER: { 1632 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1633 qb.setProjectionMap(sPeopleProjectionMap); 1634 applyRawContactsAccount(qb); 1635 String filterParam = uri.getPathSegments().get(2); 1636 qb.appendWhere(" AND " + People._ID + " IN " 1637 + getRawContactsByFilterAsNestedQuery(filterParam)); 1638 break; 1639 } 1640 1641 case GROUP_NAME_MEMBERS: 1642 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1643 qb.setProjectionMap(sPeopleProjectionMap); 1644 applyRawContactsAccount(qb); 1645 String group = uri.getPathSegments().get(2); 1646 qb.appendWhere(" AND " + buildGroupNameMatchWhereClause(group)); 1647 break; 1648 1649 case GROUP_SYSTEM_ID_MEMBERS: 1650 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1651 qb.setProjectionMap(sPeopleProjectionMap); 1652 applyRawContactsAccount(qb); 1653 String systemId = uri.getPathSegments().get(2); 1654 qb.appendWhere(" AND " + buildGroupSystemIdMatchWhereClause(systemId)); 1655 break; 1656 1657 case ORGANIZATIONS: 1658 qb.setTables(LegacyTables.ORGANIZATIONS + " organizations"); 1659 qb.setProjectionMap(sOrganizationProjectionMap); 1660 applyRawContactsAccount(qb); 1661 break; 1662 1663 case ORGANIZATIONS_ID: 1664 qb.setTables(LegacyTables.ORGANIZATIONS + " organizations"); 1665 qb.setProjectionMap(sOrganizationProjectionMap); 1666 applyRawContactsAccount(qb); 1667 qb.appendWhere(" AND " + android.provider.Contacts.Organizations._ID + "="); 1668 qb.appendWhere(uri.getPathSegments().get(1)); 1669 break; 1670 1671 case PEOPLE_ORGANIZATIONS: 1672 qb.setTables(LegacyTables.ORGANIZATIONS + " organizations"); 1673 qb.setProjectionMap(sOrganizationProjectionMap); 1674 applyRawContactsAccount(qb); 1675 qb.appendWhere(" AND " + android.provider.Contacts.Organizations.PERSON_ID + "="); 1676 qb.appendWhere(uri.getPathSegments().get(1)); 1677 break; 1678 1679 case PEOPLE_ORGANIZATIONS_ID: 1680 qb.setTables(LegacyTables.ORGANIZATIONS + " organizations"); 1681 qb.setProjectionMap(sOrganizationProjectionMap); 1682 applyRawContactsAccount(qb); 1683 qb.appendWhere(" AND " + android.provider.Contacts.Organizations.PERSON_ID + "="); 1684 qb.appendWhere(uri.getPathSegments().get(1)); 1685 qb.appendWhere(" AND " + android.provider.Contacts.Organizations._ID + "="); 1686 qb.appendWhere(uri.getPathSegments().get(3)); 1687 break; 1688 1689 case CONTACTMETHODS: 1690 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1691 qb.setProjectionMap(sContactMethodProjectionMap); 1692 applyRawContactsAccount(qb); 1693 break; 1694 1695 case CONTACTMETHODS_ID: 1696 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1697 qb.setProjectionMap(sContactMethodProjectionMap); 1698 applyRawContactsAccount(qb); 1699 qb.appendWhere(" AND " + ContactMethods._ID + "="); 1700 qb.appendWhere(uri.getPathSegments().get(1)); 1701 break; 1702 1703 case CONTACTMETHODS_EMAIL: 1704 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1705 qb.setProjectionMap(sContactMethodProjectionMap); 1706 applyRawContactsAccount(qb); 1707 qb.appendWhere(" AND " + ContactMethods.KIND + "=" 1708 + android.provider.Contacts.KIND_EMAIL); 1709 break; 1710 1711 case PEOPLE_CONTACTMETHODS: 1712 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1713 qb.setProjectionMap(sContactMethodProjectionMap); 1714 applyRawContactsAccount(qb); 1715 qb.appendWhere(" AND " + ContactMethods.PERSON_ID + "="); 1716 qb.appendWhere(uri.getPathSegments().get(1)); 1717 qb.appendWhere(" AND " + ContactMethods.KIND + " IS NOT NULL"); 1718 break; 1719 1720 case PEOPLE_CONTACTMETHODS_ID: 1721 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1722 qb.setProjectionMap(sContactMethodProjectionMap); 1723 applyRawContactsAccount(qb); 1724 qb.appendWhere(" AND " + ContactMethods.PERSON_ID + "="); 1725 qb.appendWhere(uri.getPathSegments().get(1)); 1726 qb.appendWhere(" AND " + ContactMethods._ID + "="); 1727 qb.appendWhere(uri.getPathSegments().get(3)); 1728 qb.appendWhere(" AND " + ContactMethods.KIND + " IS NOT NULL"); 1729 break; 1730 1731 case PHONES: 1732 qb.setTables(LegacyTables.PHONES + " phones"); 1733 qb.setProjectionMap(sPhoneProjectionMap); 1734 applyRawContactsAccount(qb); 1735 break; 1736 1737 case PHONES_ID: 1738 qb.setTables(LegacyTables.PHONES + " phones"); 1739 qb.setProjectionMap(sPhoneProjectionMap); 1740 applyRawContactsAccount(qb); 1741 qb.appendWhere(" AND " + android.provider.Contacts.Phones._ID + "="); 1742 qb.appendWhere(uri.getPathSegments().get(1)); 1743 break; 1744 1745 case PHONES_FILTER: 1746 qb.setTables(LegacyTables.PHONES + " phones"); 1747 qb.setProjectionMap(sPhoneProjectionMap); 1748 applyRawContactsAccount(qb); 1749 if (uri.getPathSegments().size() > 2) { 1750 String filterParam = uri.getLastPathSegment(); 1751 qb.appendWhere(" AND person ="); 1752 qb.appendWhere(mDbHelper.buildPhoneLookupAsNestedQuery(filterParam)); 1753 qb.setDistinct(true); 1754 } 1755 break; 1756 1757 case PEOPLE_PHONES: 1758 qb.setTables(LegacyTables.PHONES + " phones"); 1759 qb.setProjectionMap(sPhoneProjectionMap); 1760 applyRawContactsAccount(qb); 1761 qb.appendWhere(" AND " + android.provider.Contacts.Phones.PERSON_ID + "="); 1762 qb.appendWhere(uri.getPathSegments().get(1)); 1763 break; 1764 1765 case PEOPLE_PHONES_ID: 1766 qb.setTables(LegacyTables.PHONES + " phones"); 1767 qb.setProjectionMap(sPhoneProjectionMap); 1768 applyRawContactsAccount(qb); 1769 qb.appendWhere(" AND " + android.provider.Contacts.Phones.PERSON_ID + "="); 1770 qb.appendWhere(uri.getPathSegments().get(1)); 1771 qb.appendWhere(" AND " + android.provider.Contacts.Phones._ID + "="); 1772 qb.appendWhere(uri.getPathSegments().get(3)); 1773 break; 1774 1775 case EXTENSIONS: 1776 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1777 qb.setProjectionMap(sExtensionProjectionMap); 1778 applyRawContactsAccount(qb); 1779 break; 1780 1781 case EXTENSIONS_ID: 1782 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1783 qb.setProjectionMap(sExtensionProjectionMap); 1784 applyRawContactsAccount(qb); 1785 qb.appendWhere(" AND " + android.provider.Contacts.Extensions._ID + "="); 1786 qb.appendWhere(uri.getPathSegments().get(1)); 1787 break; 1788 1789 case PEOPLE_EXTENSIONS: 1790 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1791 qb.setProjectionMap(sExtensionProjectionMap); 1792 applyRawContactsAccount(qb); 1793 qb.appendWhere(" AND " + android.provider.Contacts.Extensions.PERSON_ID + "="); 1794 qb.appendWhere(uri.getPathSegments().get(1)); 1795 break; 1796 1797 case PEOPLE_EXTENSIONS_ID: 1798 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1799 qb.setProjectionMap(sExtensionProjectionMap); 1800 applyRawContactsAccount(qb); 1801 qb.appendWhere(" AND " + android.provider.Contacts.Extensions.PERSON_ID + "="); 1802 qb.appendWhere(uri.getPathSegments().get(1)); 1803 qb.appendWhere(" AND " + android.provider.Contacts.Extensions._ID + "="); 1804 qb.appendWhere(uri.getPathSegments().get(3)); 1805 break; 1806 1807 case GROUPS: 1808 qb.setTables(LegacyTables.GROUPS + " groups"); 1809 qb.setProjectionMap(sGroupProjectionMap); 1810 applyGroupAccount(qb); 1811 break; 1812 1813 case GROUPS_ID: 1814 qb.setTables(LegacyTables.GROUPS + " groups"); 1815 qb.setProjectionMap(sGroupProjectionMap); 1816 applyGroupAccount(qb); 1817 qb.appendWhere(" AND " + android.provider.Contacts.Groups._ID + "="); 1818 qb.appendWhere(uri.getPathSegments().get(1)); 1819 break; 1820 1821 case GROUPMEMBERSHIP: 1822 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1823 qb.setProjectionMap(sGroupMembershipProjectionMap); 1824 applyRawContactsAccount(qb); 1825 break; 1826 1827 case GROUPMEMBERSHIP_ID: 1828 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1829 qb.setProjectionMap(sGroupMembershipProjectionMap); 1830 applyRawContactsAccount(qb); 1831 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership._ID + "="); 1832 qb.appendWhere(uri.getPathSegments().get(1)); 1833 break; 1834 1835 case PEOPLE_GROUPMEMBERSHIP: 1836 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1837 qb.setProjectionMap(sGroupMembershipProjectionMap); 1838 applyRawContactsAccount(qb); 1839 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership.PERSON_ID + "="); 1840 qb.appendWhere(uri.getPathSegments().get(1)); 1841 break; 1842 1843 case PEOPLE_GROUPMEMBERSHIP_ID: 1844 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1845 qb.setProjectionMap(sGroupMembershipProjectionMap); 1846 applyRawContactsAccount(qb); 1847 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership.PERSON_ID + "="); 1848 qb.appendWhere(uri.getPathSegments().get(1)); 1849 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership._ID + "="); 1850 qb.appendWhere(uri.getPathSegments().get(3)); 1851 break; 1852 1853 case PEOPLE_PHOTO: 1854 qb.setTables(LegacyTables.PHOTOS + " photos"); 1855 qb.setProjectionMap(sPhotoProjectionMap); 1856 applyRawContactsAccount(qb); 1857 qb.appendWhere(" AND " + android.provider.Contacts.Photos.PERSON_ID + "="); 1858 qb.appendWhere(uri.getPathSegments().get(1)); 1859 limit = "1"; 1860 break; 1861 1862 case PHOTOS: 1863 qb.setTables(LegacyTables.PHOTOS + " photos"); 1864 qb.setProjectionMap(sPhotoProjectionMap); 1865 applyRawContactsAccount(qb); 1866 break; 1867 1868 case PHOTOS_ID: 1869 qb.setTables(LegacyTables.PHOTOS + " photos"); 1870 qb.setProjectionMap(sPhotoProjectionMap); 1871 applyRawContactsAccount(qb); 1872 qb.appendWhere(" AND " + android.provider.Contacts.Photos._ID + "="); 1873 qb.appendWhere(uri.getPathSegments().get(1)); 1874 break; 1875 1876 case SEARCH_SUGGESTIONS: 1877 return mGlobalSearchSupport.handleSearchSuggestionsQuery( 1878 db, uri, projection, limit, null); 1879 1880 case SEARCH_SHORTCUT: { 1881 String lookupKey = uri.getLastPathSegment(); 1882 String filter = ContactsProvider2.getQueryParameter(uri, "filter"); 1883 return mGlobalSearchSupport.handleSearchShortcutRefresh( 1884 db, projection, lookupKey, filter, null); 1885 } 1886 1887 case LIVE_FOLDERS_PEOPLE: 1888 return mContactsProvider.query(LIVE_FOLDERS_CONTACTS_URI, 1889 projection, selection, selectionArgs, sortOrder); 1890 1891 case LIVE_FOLDERS_PEOPLE_WITH_PHONES: 1892 return mContactsProvider.query(LIVE_FOLDERS_CONTACTS_WITH_PHONES_URI, 1893 projection, selection, selectionArgs, sortOrder); 1894 1895 case LIVE_FOLDERS_PEOPLE_FAVORITES: 1896 return mContactsProvider.query(LIVE_FOLDERS_CONTACTS_FAVORITES_URI, 1897 projection, selection, selectionArgs, sortOrder); 1898 1899 case LIVE_FOLDERS_PEOPLE_GROUP_NAME: 1900 return mContactsProvider.query(Uri.withAppendedPath(LIVE_FOLDERS_CONTACTS_URI, 1901 Uri.encode(uri.getLastPathSegment())), 1902 projection, selection, selectionArgs, sortOrder); 1903 1904 case DELETED_PEOPLE: 1905 case DELETED_GROUPS: 1906 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 1907 1908 case SETTINGS: 1909 copySettingsToLegacySettings(); 1910 qb.setTables(LegacyTables.SETTINGS); 1911 break; 1912 1913 default: 1914 throw new IllegalArgumentException(mDbHelper.exceptionMessage(uri)); 1915 } 1916 1917 // Perform the query and set the notification uri 1918 final Cursor c = qb.query(db, projection, selection, selectionArgs, 1919 groupBy, null, sortOrder, limit); 1920 if (c != null) { 1921 c.setNotificationUri(mContext.getContentResolver(), 1922 android.provider.Contacts.CONTENT_URI); 1923 } 1924 return c; 1925 } 1926 1927 private void applyRawContactsAccount(SQLiteQueryBuilder qb) { 1928 StringBuilder sb = new StringBuilder(); 1929 appendRawContactsAccount(sb); 1930 qb.appendWhere(sb.toString()); 1931 } 1932 1933 private void appendRawContactsAccount(StringBuilder sb) { 1934 if (mAccount != null) { 1935 sb.append(RawContacts.ACCOUNT_NAME + "="); 1936 DatabaseUtils.appendEscapedSQLString(sb, mAccount.name); 1937 sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 1938 DatabaseUtils.appendEscapedSQLString(sb, mAccount.type); 1939 } else { 1940 sb.append(RawContacts.ACCOUNT_NAME + " IS NULL" + 1941 " AND " + RawContacts.ACCOUNT_TYPE + " IS NULL"); 1942 } 1943 } 1944 1945 private void applyGroupAccount(SQLiteQueryBuilder qb) { 1946 StringBuilder sb = new StringBuilder(); 1947 appendGroupAccount(sb); 1948 qb.appendWhere(sb.toString()); 1949 } 1950 1951 private void appendGroupAccount(StringBuilder sb) { 1952 if (mAccount != null) { 1953 sb.append(Groups.ACCOUNT_NAME + "="); 1954 DatabaseUtils.appendEscapedSQLString(sb, mAccount.name); 1955 sb.append(" AND " + Groups.ACCOUNT_TYPE + "="); 1956 DatabaseUtils.appendEscapedSQLString(sb, mAccount.type); 1957 } else { 1958 sb.append(Groups.ACCOUNT_NAME + " IS NULL" + 1959 " AND " + Groups.ACCOUNT_TYPE + " IS NULL"); 1960 } 1961 } 1962 1963 /** 1964 * Build a WHERE clause that restricts the query to match people that are a member of 1965 * a group with a particular name. The projection map of the query must include 1966 * {@link People#_ID}. 1967 * 1968 * @param groupName The name of the group 1969 * @return The where clause. 1970 */ 1971 private String buildGroupNameMatchWhereClause(String groupName) { 1972 return "people._id IN " 1973 + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 1974 + " FROM " + Tables.DATA_JOIN_MIMETYPES 1975 + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE 1976 + "' AND " + GroupMembership.GROUP_ROW_ID + "=" 1977 + "(SELECT " + Tables.GROUPS + "." + Groups._ID 1978 + " FROM " + Tables.GROUPS 1979 + " WHERE " + Groups.TITLE + "=" 1980 + DatabaseUtils.sqlEscapeString(groupName) + "))"; 1981 } 1982 1983 /** 1984 * Build a WHERE clause that restricts the query to match people that are a member of 1985 * a group with a particular system id. The projection map of the query must include 1986 * {@link People#_ID}. 1987 * 1988 * @param groupName The name of the group 1989 * @return The where clause. 1990 */ 1991 private String buildGroupSystemIdMatchWhereClause(String systemId) { 1992 return "people._id IN " 1993 + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 1994 + " FROM " + Tables.DATA_JOIN_MIMETYPES 1995 + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE 1996 + "' AND " + GroupMembership.GROUP_ROW_ID + "=" 1997 + "(SELECT " + Tables.GROUPS + "." + Groups._ID 1998 + " FROM " + Tables.GROUPS 1999 + " WHERE " + Groups.SYSTEM_ID + "=" 2000 + DatabaseUtils.sqlEscapeString(systemId) + "))"; 2001 } 2002 2003 private String getRawContactsByFilterAsNestedQuery(String filterParam) { 2004 StringBuilder sb = new StringBuilder(); 2005 String normalizedName = NameNormalizer.normalize(filterParam); 2006 if (TextUtils.isEmpty(normalizedName)) { 2007 // Effectively an empty IN clause - SQL syntax does not allow an actual empty list here 2008 sb.append("(0)"); 2009 } else { 2010 sb.append("(" + 2011 "SELECT " + NameLookupColumns.RAW_CONTACT_ID + 2012 " FROM " + Tables.NAME_LOOKUP + 2013 " WHERE " + NameLookupColumns.NORMALIZED_NAME + 2014 " GLOB '"); 2015 // Should not use a "?" argument placeholder here, because 2016 // that would prevent the SQL optimizer from using the index on NORMALIZED_NAME. 2017 sb.append(normalizedName); 2018 sb.append("*' AND " + NameLookupColumns.NAME_TYPE + " IN (" 2019 + NameLookupType.NAME_COLLATION_KEY + "," 2020 + NameLookupType.NICKNAME); 2021 if (true) { 2022 sb.append("," + NameLookupType.EMAIL_BASED_NICKNAME); 2023 } 2024 sb.append("))"); 2025 } 2026 return sb.toString(); 2027 } 2028 2029 /** 2030 * Called when a change has been made. 2031 * 2032 * @param uri the uri that the change was made to 2033 */ 2034 private void onChange(Uri uri) { 2035 mContext.getContentResolver().notifyChange(android.provider.Contacts.CONTENT_URI, null); 2036 } 2037 2038 public String getType(Uri uri) { 2039 int match = sUriMatcher.match(uri); 2040 switch (match) { 2041 case EXTENSIONS: 2042 case PEOPLE_EXTENSIONS: 2043 return Extensions.CONTENT_TYPE; 2044 case EXTENSIONS_ID: 2045 case PEOPLE_EXTENSIONS_ID: 2046 return Extensions.CONTENT_ITEM_TYPE; 2047 case PEOPLE: 2048 return "vnd.android.cursor.dir/person"; 2049 case PEOPLE_ID: 2050 return "vnd.android.cursor.item/person"; 2051 case PEOPLE_PHONES: 2052 return "vnd.android.cursor.dir/phone"; 2053 case PEOPLE_PHONES_ID: 2054 return "vnd.android.cursor.item/phone"; 2055 case PEOPLE_CONTACTMETHODS: 2056 return "vnd.android.cursor.dir/contact-methods"; 2057 case PEOPLE_CONTACTMETHODS_ID: 2058 return getContactMethodType(uri); 2059 case PHONES: 2060 return "vnd.android.cursor.dir/phone"; 2061 case PHONES_ID: 2062 return "vnd.android.cursor.item/phone"; 2063 case PHONES_FILTER: 2064 return "vnd.android.cursor.dir/phone"; 2065 case PHOTOS_ID: 2066 return "vnd.android.cursor.item/photo"; 2067 case PHOTOS: 2068 return "vnd.android.cursor.dir/photo"; 2069 case PEOPLE_PHOTO: 2070 return "vnd.android.cursor.item/photo"; 2071 case CONTACTMETHODS: 2072 return "vnd.android.cursor.dir/contact-methods"; 2073 case CONTACTMETHODS_ID: 2074 return getContactMethodType(uri); 2075 case ORGANIZATIONS: 2076 return "vnd.android.cursor.dir/organizations"; 2077 case ORGANIZATIONS_ID: 2078 return "vnd.android.cursor.item/organization"; 2079 case SEARCH_SUGGESTIONS: 2080 return SearchManager.SUGGEST_MIME_TYPE; 2081 case SEARCH_SHORTCUT: 2082 return SearchManager.SHORTCUT_MIME_TYPE; 2083 default: 2084 throw new IllegalArgumentException(mDbHelper.exceptionMessage(uri)); 2085 } 2086 } 2087 2088 private String getContactMethodType(Uri url) { 2089 String mime = null; 2090 2091 Cursor c = query(url, new String[] {ContactMethods.KIND}, null, null, null, null); 2092 if (c != null) { 2093 try { 2094 if (c.moveToFirst()) { 2095 int kind = c.getInt(0); 2096 switch (kind) { 2097 case android.provider.Contacts.KIND_EMAIL: 2098 mime = "vnd.android.cursor.item/email"; 2099 break; 2100 2101 case android.provider.Contacts.KIND_IM: 2102 mime = "vnd.android.cursor.item/jabber-im"; 2103 break; 2104 2105 case android.provider.Contacts.KIND_POSTAL: 2106 mime = "vnd.android.cursor.item/postal-address"; 2107 break; 2108 } 2109 } 2110 } finally { 2111 c.close(); 2112 } 2113 } 2114 return mime; 2115 } 2116 } 2117