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