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 com.android.providers.contacts.ContactsDatabaseHelper.DataColumns; 19 import com.android.providers.contacts.ContactsDatabaseHelper.ExtensionsColumns; 20 import com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns; 21 import com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns; 22 import com.android.providers.contacts.ContactsDatabaseHelper.PhoneColumns; 23 import com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns; 24 import com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 25 import com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; 26 import com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns; 27 import com.android.providers.contacts.ContactsDatabaseHelper.Tables; 28 29 import android.accounts.Account; 30 import android.app.SearchManager; 31 import android.content.ContentUris; 32 import android.content.ContentValues; 33 import android.content.Context; 34 import android.content.UriMatcher; 35 import android.database.Cursor; 36 import android.database.DatabaseUtils; 37 import android.database.SQLException; 38 import android.database.sqlite.SQLiteDatabase; 39 import android.database.sqlite.SQLiteDoneException; 40 import android.database.sqlite.SQLiteQueryBuilder; 41 import android.database.sqlite.SQLiteStatement; 42 import android.net.Uri; 43 import android.provider.BaseColumns; 44 import android.provider.ContactsContract; 45 import android.provider.Contacts.ContactMethods; 46 import android.provider.Contacts.Extensions; 47 import android.provider.Contacts.People; 48 import android.provider.ContactsContract.Contacts; 49 import android.provider.ContactsContract.Data; 50 import android.provider.ContactsContract.Groups; 51 import android.provider.ContactsContract.RawContacts; 52 import android.provider.ContactsContract.Settings; 53 import android.provider.ContactsContract.StatusUpdates; 54 import android.provider.ContactsContract.CommonDataKinds.Email; 55 import android.provider.ContactsContract.CommonDataKinds.GroupMembership; 56 import android.provider.ContactsContract.CommonDataKinds.Im; 57 import android.provider.ContactsContract.CommonDataKinds.Note; 58 import android.provider.ContactsContract.CommonDataKinds.Organization; 59 import android.provider.ContactsContract.CommonDataKinds.Phone; 60 import android.provider.ContactsContract.CommonDataKinds.Photo; 61 import android.provider.ContactsContract.CommonDataKinds.StructuredName; 62 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 63 import android.util.Log; 64 65 import java.util.HashMap; 66 import java.util.Locale; 67 68 @SuppressWarnings("deprecation") 69 public class LegacyApiSupport { 70 71 private static final String TAG = "ContactsProviderV1"; 72 73 private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 74 75 private static final int PEOPLE = 1; 76 private static final int PEOPLE_ID = 2; 77 private static final int PEOPLE_UPDATE_CONTACT_TIME = 3; 78 private static final int ORGANIZATIONS = 4; 79 private static final int ORGANIZATIONS_ID = 5; 80 private static final int PEOPLE_CONTACTMETHODS = 6; 81 private static final int PEOPLE_CONTACTMETHODS_ID = 7; 82 private static final int CONTACTMETHODS = 8; 83 private static final int CONTACTMETHODS_ID = 9; 84 private static final int PEOPLE_PHONES = 10; 85 private static final int PEOPLE_PHONES_ID = 11; 86 private static final int PHONES = 12; 87 private static final int PHONES_ID = 13; 88 private static final int EXTENSIONS = 14; 89 private static final int EXTENSIONS_ID = 15; 90 private static final int PEOPLE_EXTENSIONS = 16; 91 private static final int PEOPLE_EXTENSIONS_ID = 17; 92 private static final int GROUPS = 18; 93 private static final int GROUPS_ID = 19; 94 private static final int GROUPMEMBERSHIP = 20; 95 private static final int GROUPMEMBERSHIP_ID = 21; 96 private static final int PEOPLE_GROUPMEMBERSHIP = 22; 97 private static final int PEOPLE_GROUPMEMBERSHIP_ID = 23; 98 private static final int PEOPLE_PHOTO = 24; 99 private static final int PHOTOS = 25; 100 private static final int PHOTOS_ID = 26; 101 private static final int PEOPLE_FILTER = 29; 102 private static final int DELETED_PEOPLE = 30; 103 private static final int DELETED_GROUPS = 31; 104 private static final int SEARCH_SUGGESTIONS = 32; 105 private static final int SEARCH_SHORTCUT = 33; 106 private static final int PHONES_FILTER = 34; 107 private static final int LIVE_FOLDERS_PEOPLE = 35; 108 private static final int LIVE_FOLDERS_PEOPLE_GROUP_NAME = 36; 109 private static final int LIVE_FOLDERS_PEOPLE_WITH_PHONES = 37; 110 private static final int LIVE_FOLDERS_PEOPLE_FAVORITES = 38; 111 private static final int CONTACTMETHODS_EMAIL = 39; 112 private static final int GROUP_NAME_MEMBERS = 40; 113 private static final int GROUP_SYSTEM_ID_MEMBERS = 41; 114 private static final int PEOPLE_ORGANIZATIONS = 42; 115 private static final int PEOPLE_ORGANIZATIONS_ID = 43; 116 private static final int SETTINGS = 44; 117 118 private static final String PEOPLE_JOINS = 119 " LEFT OUTER JOIN data name ON (raw_contacts._id = name.raw_contact_id" 120 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = name.mimetype_id)" 121 + "='" + StructuredName.CONTENT_ITEM_TYPE + "')" 122 + " LEFT OUTER JOIN data organization ON (raw_contacts._id = organization.raw_contact_id" 123 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = organization.mimetype_id)" 124 + "='" + Organization.CONTENT_ITEM_TYPE + "' AND organization.is_primary)" 125 + " LEFT OUTER JOIN data email ON (raw_contacts._id = email.raw_contact_id" 126 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = email.mimetype_id)" 127 + "='" + Email.CONTENT_ITEM_TYPE + "' AND email.is_primary)" 128 + " LEFT OUTER JOIN data note ON (raw_contacts._id = note.raw_contact_id" 129 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = note.mimetype_id)" 130 + "='" + Note.CONTENT_ITEM_TYPE + "')" 131 + " LEFT OUTER JOIN data phone ON (raw_contacts._id = phone.raw_contact_id" 132 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = phone.mimetype_id)" 133 + "='" + Phone.CONTENT_ITEM_TYPE + "' AND phone.is_primary)"; 134 135 public static final String DATA_JOINS = 136 " JOIN mimetypes ON (mimetypes._id = data.mimetype_id)" 137 + " JOIN raw_contacts ON (raw_contacts._id = data.raw_contact_id)" 138 + PEOPLE_JOINS; 139 140 public static final String PRESENCE_JOINS = 141 " LEFT OUTER JOIN " + Tables.PRESENCE + 142 " ON (" + Tables.PRESENCE + "." + StatusUpdates.DATA_ID + "=" + 143 "(SELECT MAX(" + StatusUpdates.DATA_ID + ")" + 144 " FROM " + Tables.PRESENCE + 145 " WHERE people._id = " + PresenceColumns.RAW_CONTACT_ID + ")" + 146 " )"; 147 148 private static final String PHONETIC_NAME_SQL = "trim(trim(" 149 + "ifnull(name." + StructuredName.PHONETIC_GIVEN_NAME + ",' ')||' '||" 150 + "ifnull(name." + StructuredName.PHONETIC_MIDDLE_NAME + ",' '))||' '||" 151 + "ifnull(name." + StructuredName.PHONETIC_FAMILY_NAME + ",' ')) "; 152 153 private static final String CONTACT_METHOD_KIND_SQL = 154 "CAST ((CASE WHEN mimetype='" + Email.CONTENT_ITEM_TYPE + "'" 155 + " THEN " + android.provider.Contacts.KIND_EMAIL 156 + " ELSE" 157 + " (CASE WHEN mimetype='" + Im.CONTENT_ITEM_TYPE +"'" 158 + " THEN " + android.provider.Contacts.KIND_IM 159 + " ELSE" 160 + " (CASE WHEN mimetype='" + StructuredPostal.CONTENT_ITEM_TYPE + "'" 161 + " THEN " + android.provider.Contacts.KIND_POSTAL 162 + " ELSE" 163 + " NULL" 164 + " END)" 165 + " END)" 166 + " END) AS INTEGER)"; 167 168 private static final String IM_PROTOCOL_SQL = 169 "(CASE WHEN " + StatusUpdates.PROTOCOL + "=" + Im.PROTOCOL_CUSTOM 170 + " THEN 'custom:'||" + StatusUpdates.CUSTOM_PROTOCOL 171 + " ELSE 'pre:'||" + StatusUpdates.PROTOCOL 172 + " END)"; 173 174 private static String CONTACT_METHOD_DATA_SQL = 175 "(CASE WHEN " + Data.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'" 176 + " THEN (CASE WHEN " + Tables.DATA + "." + Im.PROTOCOL + "=" + Im.PROTOCOL_CUSTOM 177 + " THEN 'custom:'||" + Tables.DATA + "." + Im.CUSTOM_PROTOCOL 178 + " ELSE 'pre:'||" + Tables.DATA + "." + Im.PROTOCOL 179 + " END)" 180 + " ELSE " + Tables.DATA + "." + Email.DATA 181 + " END)"; 182 183 private static final Uri LIVE_FOLDERS_CONTACTS_URI = Uri.withAppendedPath( 184 ContactsContract.AUTHORITY_URI, "live_folders/contacts"); 185 186 private static final Uri LIVE_FOLDERS_CONTACTS_WITH_PHONES_URI = Uri.withAppendedPath( 187 ContactsContract.AUTHORITY_URI, "live_folders/contacts_with_phones"); 188 189 private static final Uri LIVE_FOLDERS_CONTACTS_FAVORITES_URI = Uri.withAppendedPath( 190 ContactsContract.AUTHORITY_URI, "live_folders/favorites"); 191 192 private static final String CONTACTS_UPDATE_LASTTIMECONTACTED = 193 "UPDATE " + Tables.CONTACTS + 194 " SET " + Contacts.LAST_TIME_CONTACTED + "=? " + 195 "WHERE " + Contacts._ID + "=?"; 196 private static final String RAWCONTACTS_UPDATE_LASTTIMECONTACTED = 197 "UPDATE " + Tables.RAW_CONTACTS + " SET " 198 + RawContacts.LAST_TIME_CONTACTED + "=? WHERE " 199 + RawContacts._ID + "=?"; 200 201 private String[] mSelectionArgs1 = new String[1]; 202 private String[] mSelectionArgs2 = new String[2]; 203 204 public interface LegacyTables { 205 public static final String PEOPLE = "view_v1_people"; 206 public static final String PEOPLE_JOIN_PRESENCE = "view_v1_people people " + PRESENCE_JOINS; 207 public static final String GROUPS = "view_v1_groups"; 208 public static final String ORGANIZATIONS = "view_v1_organizations"; 209 public static final String CONTACT_METHODS = "view_v1_contact_methods"; 210 public static final String PHONES = "view_v1_phones"; 211 public static final String EXTENSIONS = "view_v1_extensions"; 212 public static final String GROUP_MEMBERSHIP = "view_v1_group_membership"; 213 public static final String PHOTOS = "view_v1_photos"; 214 public static final String SETTINGS = "v1_settings"; 215 } 216 217 private static final String[] ORGANIZATION_MIME_TYPES = new String[] { 218 Organization.CONTENT_ITEM_TYPE 219 }; 220 221 private static final String[] CONTACT_METHOD_MIME_TYPES = new String[] { 222 Email.CONTENT_ITEM_TYPE, 223 Im.CONTENT_ITEM_TYPE, 224 StructuredPostal.CONTENT_ITEM_TYPE, 225 }; 226 227 private static final String[] PHONE_MIME_TYPES = new String[] { 228 Phone.CONTENT_ITEM_TYPE 229 }; 230 231 private static final String[] PHOTO_MIME_TYPES = new String[] { 232 Photo.CONTENT_ITEM_TYPE 233 }; 234 235 private static final String[] GROUP_MEMBERSHIP_MIME_TYPES = new String[] { 236 GroupMembership.CONTENT_ITEM_TYPE 237 }; 238 239 private static final String[] EXTENSION_MIME_TYPES = new String[] { 240 android.provider.Contacts.Extensions.CONTENT_ITEM_TYPE 241 }; 242 243 private interface IdQuery { 244 String[] COLUMNS = { BaseColumns._ID }; 245 246 int _ID = 0; 247 } 248 249 /** 250 * A custom data row that is used to store legacy photo data fields no 251 * longer directly supported by the API. 252 */ 253 private interface LegacyPhotoData { 254 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo_v1_extras"; 255 256 public static final String PHOTO_DATA_ID = Data.DATA1; 257 public static final String LOCAL_VERSION = Data.DATA2; 258 public static final String DOWNLOAD_REQUIRED = Data.DATA3; 259 public static final String EXISTS_ON_SERVER = Data.DATA4; 260 public static final String SYNC_ERROR = Data.DATA5; 261 } 262 263 public static final String LEGACY_PHOTO_JOIN = 264 " LEFT OUTER JOIN data legacy_photo ON (raw_contacts._id = legacy_photo.raw_contact_id" 265 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = legacy_photo.mimetype_id)" 266 + "='" + LegacyPhotoData.CONTENT_ITEM_TYPE + "'" 267 + " AND " + DataColumns.CONCRETE_ID + " = legacy_photo." + LegacyPhotoData.PHOTO_DATA_ID 268 + ")"; 269 270 private static final HashMap<String, String> sPeopleProjectionMap; 271 private static final HashMap<String, String> sOrganizationProjectionMap; 272 private static final HashMap<String, String> sContactMethodProjectionMap; 273 private static final HashMap<String, String> sPhoneProjectionMap; 274 private static final HashMap<String, String> sExtensionProjectionMap; 275 private static final HashMap<String, String> sGroupProjectionMap; 276 private static final HashMap<String, String> sGroupMembershipProjectionMap; 277 private static final HashMap<String, String> sPhotoProjectionMap; 278 279 static { 280 281 // Contacts URI matching table 282 UriMatcher matcher = sUriMatcher; 283 284 String authority = android.provider.Contacts.AUTHORITY; 285 matcher.addURI(authority, "extensions", EXTENSIONS); 286 matcher.addURI(authority, "extensions/#", EXTENSIONS_ID); 287 matcher.addURI(authority, "groups", GROUPS); 288 matcher.addURI(authority, "groups/#", GROUPS_ID); 289 matcher.addURI(authority, "groups/name/*/members", GROUP_NAME_MEMBERS); 290 // matcher.addURI(authority, "groups/name/*/members/filter/*", 291 // GROUP_NAME_MEMBERS_FILTER); 292 matcher.addURI(authority, "groups/system_id/*/members", GROUP_SYSTEM_ID_MEMBERS); 293 // matcher.addURI(authority, "groups/system_id/*/members/filter/*", 294 // GROUP_SYSTEM_ID_MEMBERS_FILTER); 295 matcher.addURI(authority, "groupmembership", GROUPMEMBERSHIP); 296 matcher.addURI(authority, "groupmembership/#", GROUPMEMBERSHIP_ID); 297 // matcher.addURI(authority, "groupmembershipraw", GROUPMEMBERSHIP_RAW); 298 matcher.addURI(authority, "people", PEOPLE); 299 // matcher.addURI(authority, "people/strequent", PEOPLE_STREQUENT); 300 // matcher.addURI(authority, "people/strequent/filter/*", PEOPLE_STREQUENT_FILTER); 301 matcher.addURI(authority, "people/filter/*", PEOPLE_FILTER); 302 // matcher.addURI(authority, "people/with_phones_filter/*", 303 // PEOPLE_WITH_PHONES_FILTER); 304 // matcher.addURI(authority, "people/with_email_or_im_filter/*", 305 // PEOPLE_WITH_EMAIL_OR_IM_FILTER); 306 matcher.addURI(authority, "people/#", PEOPLE_ID); 307 matcher.addURI(authority, "people/#/extensions", PEOPLE_EXTENSIONS); 308 matcher.addURI(authority, "people/#/extensions/#", PEOPLE_EXTENSIONS_ID); 309 matcher.addURI(authority, "people/#/phones", PEOPLE_PHONES); 310 matcher.addURI(authority, "people/#/phones/#", PEOPLE_PHONES_ID); 311 // matcher.addURI(authority, "people/#/phones_with_presence", 312 // PEOPLE_PHONES_WITH_PRESENCE); 313 matcher.addURI(authority, "people/#/photo", PEOPLE_PHOTO); 314 // matcher.addURI(authority, "people/#/photo/data", PEOPLE_PHOTO_DATA); 315 matcher.addURI(authority, "people/#/contact_methods", PEOPLE_CONTACTMETHODS); 316 // matcher.addURI(authority, "people/#/contact_methods_with_presence", 317 // PEOPLE_CONTACTMETHODS_WITH_PRESENCE); 318 matcher.addURI(authority, "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID); 319 matcher.addURI(authority, "people/#/organizations", PEOPLE_ORGANIZATIONS); 320 matcher.addURI(authority, "people/#/organizations/#", PEOPLE_ORGANIZATIONS_ID); 321 matcher.addURI(authority, "people/#/groupmembership", PEOPLE_GROUPMEMBERSHIP); 322 matcher.addURI(authority, "people/#/groupmembership/#", PEOPLE_GROUPMEMBERSHIP_ID); 323 // matcher.addURI(authority, "people/raw", PEOPLE_RAW); 324 // matcher.addURI(authority, "people/owner", PEOPLE_OWNER); 325 matcher.addURI(authority, "people/#/update_contact_time", 326 PEOPLE_UPDATE_CONTACT_TIME); 327 matcher.addURI(authority, "deleted_people", DELETED_PEOPLE); 328 matcher.addURI(authority, "deleted_groups", DELETED_GROUPS); 329 matcher.addURI(authority, "phones", PHONES); 330 // matcher.addURI(authority, "phones_with_presence", PHONES_WITH_PRESENCE); 331 matcher.addURI(authority, "phones/filter/*", PHONES_FILTER); 332 // matcher.addURI(authority, "phones/filter_name/*", PHONES_FILTER_NAME); 333 // matcher.addURI(authority, "phones/mobile_filter_name/*", 334 // PHONES_MOBILE_FILTER_NAME); 335 matcher.addURI(authority, "phones/#", PHONES_ID); 336 matcher.addURI(authority, "photos", PHOTOS); 337 matcher.addURI(authority, "photos/#", PHOTOS_ID); 338 matcher.addURI(authority, "contact_methods", CONTACTMETHODS); 339 matcher.addURI(authority, "contact_methods/email", CONTACTMETHODS_EMAIL); 340 // matcher.addURI(authority, "contact_methods/email/*", CONTACTMETHODS_EMAIL_FILTER); 341 matcher.addURI(authority, "contact_methods/#", CONTACTMETHODS_ID); 342 // matcher.addURI(authority, "contact_methods/with_presence", 343 // CONTACTMETHODS_WITH_PRESENCE); 344 matcher.addURI(authority, "organizations", ORGANIZATIONS); 345 matcher.addURI(authority, "organizations/#", ORGANIZATIONS_ID); 346 // matcher.addURI(authority, "voice_dialer_timestamp", VOICE_DIALER_TIMESTAMP); 347 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_QUERY, 348 SEARCH_SUGGESTIONS); 349 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 350 SEARCH_SUGGESTIONS); 351 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 352 SEARCH_SHORTCUT); 353 matcher.addURI(authority, "settings", SETTINGS); 354 355 matcher.addURI(authority, "live_folders/people", LIVE_FOLDERS_PEOPLE); 356 matcher.addURI(authority, "live_folders/people/*", 357 LIVE_FOLDERS_PEOPLE_GROUP_NAME); 358 matcher.addURI(authority, "live_folders/people_with_phones", 359 LIVE_FOLDERS_PEOPLE_WITH_PHONES); 360 matcher.addURI(authority, "live_folders/favorites", 361 LIVE_FOLDERS_PEOPLE_FAVORITES); 362 363 364 HashMap<String, String> peopleProjectionMap = new HashMap<String, String>(); 365 peopleProjectionMap.put(People.NAME, People.NAME); 366 peopleProjectionMap.put(People.DISPLAY_NAME, People.DISPLAY_NAME); 367 peopleProjectionMap.put(People.PHONETIC_NAME, People.PHONETIC_NAME); 368 peopleProjectionMap.put(People.NOTES, People.NOTES); 369 peopleProjectionMap.put(People.TIMES_CONTACTED, People.TIMES_CONTACTED); 370 peopleProjectionMap.put(People.LAST_TIME_CONTACTED, People.LAST_TIME_CONTACTED); 371 peopleProjectionMap.put(People.CUSTOM_RINGTONE, People.CUSTOM_RINGTONE); 372 peopleProjectionMap.put(People.SEND_TO_VOICEMAIL, People.SEND_TO_VOICEMAIL); 373 peopleProjectionMap.put(People.STARRED, People.STARRED); 374 peopleProjectionMap.put(People.PRIMARY_ORGANIZATION_ID, People.PRIMARY_ORGANIZATION_ID); 375 peopleProjectionMap.put(People.PRIMARY_EMAIL_ID, People.PRIMARY_EMAIL_ID); 376 peopleProjectionMap.put(People.PRIMARY_PHONE_ID, People.PRIMARY_PHONE_ID); 377 378 sPeopleProjectionMap = new HashMap<String, String>(peopleProjectionMap); 379 sPeopleProjectionMap.put(People._ID, People._ID); 380 sPeopleProjectionMap.put(People.NUMBER, People.NUMBER); 381 sPeopleProjectionMap.put(People.TYPE, People.TYPE); 382 sPeopleProjectionMap.put(People.LABEL, People.LABEL); 383 sPeopleProjectionMap.put(People.NUMBER_KEY, People.NUMBER_KEY); 384 sPeopleProjectionMap.put(People.IM_PROTOCOL, IM_PROTOCOL_SQL + " AS " + People.IM_PROTOCOL); 385 sPeopleProjectionMap.put(People.IM_HANDLE, People.IM_HANDLE); 386 sPeopleProjectionMap.put(People.IM_ACCOUNT, People.IM_ACCOUNT); 387 sPeopleProjectionMap.put(People.PRESENCE_STATUS, People.PRESENCE_STATUS); 388 sPeopleProjectionMap.put(People.PRESENCE_CUSTOM_STATUS, 389 "(SELECT " + StatusUpdates.STATUS + 390 " FROM " + Tables.STATUS_UPDATES + 391 " JOIN " + Tables.DATA + 392 " ON(" + StatusUpdatesColumns.DATA_ID + "=" + DataColumns.CONCRETE_ID + ")" + 393 " WHERE " + DataColumns.CONCRETE_RAW_CONTACT_ID + "=people." + People._ID + 394 " ORDER BY " + StatusUpdates.STATUS_TIMESTAMP + " DESC " + 395 " LIMIT 1" + 396 ") AS " + People.PRESENCE_CUSTOM_STATUS); 397 398 sOrganizationProjectionMap = new HashMap<String, String>(); 399 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations._ID, 400 android.provider.Contacts.Organizations._ID); 401 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.PERSON_ID, 402 android.provider.Contacts.Organizations.PERSON_ID); 403 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.ISPRIMARY, 404 android.provider.Contacts.Organizations.ISPRIMARY); 405 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.COMPANY, 406 android.provider.Contacts.Organizations.COMPANY); 407 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.TYPE, 408 android.provider.Contacts.Organizations.TYPE); 409 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.LABEL, 410 android.provider.Contacts.Organizations.LABEL); 411 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.TITLE, 412 android.provider.Contacts.Organizations.TITLE); 413 414 sContactMethodProjectionMap = new HashMap<String, String>(peopleProjectionMap); 415 sContactMethodProjectionMap.put(ContactMethods._ID, ContactMethods._ID); 416 sContactMethodProjectionMap.put(ContactMethods.PERSON_ID, ContactMethods.PERSON_ID); 417 sContactMethodProjectionMap.put(ContactMethods.KIND, ContactMethods.KIND); 418 sContactMethodProjectionMap.put(ContactMethods.ISPRIMARY, ContactMethods.ISPRIMARY); 419 sContactMethodProjectionMap.put(ContactMethods.TYPE, ContactMethods.TYPE); 420 sContactMethodProjectionMap.put(ContactMethods.DATA, ContactMethods.DATA); 421 sContactMethodProjectionMap.put(ContactMethods.LABEL, ContactMethods.LABEL); 422 sContactMethodProjectionMap.put(ContactMethods.AUX_DATA, ContactMethods.AUX_DATA); 423 424 sPhoneProjectionMap = new HashMap<String, String>(peopleProjectionMap); 425 sPhoneProjectionMap.put(android.provider.Contacts.Phones._ID, 426 android.provider.Contacts.Phones._ID); 427 sPhoneProjectionMap.put(android.provider.Contacts.Phones.PERSON_ID, 428 android.provider.Contacts.Phones.PERSON_ID); 429 sPhoneProjectionMap.put(android.provider.Contacts.Phones.ISPRIMARY, 430 android.provider.Contacts.Phones.ISPRIMARY); 431 sPhoneProjectionMap.put(android.provider.Contacts.Phones.NUMBER, 432 android.provider.Contacts.Phones.NUMBER); 433 sPhoneProjectionMap.put(android.provider.Contacts.Phones.TYPE, 434 android.provider.Contacts.Phones.TYPE); 435 sPhoneProjectionMap.put(android.provider.Contacts.Phones.LABEL, 436 android.provider.Contacts.Phones.LABEL); 437 sPhoneProjectionMap.put(android.provider.Contacts.Phones.NUMBER_KEY, 438 android.provider.Contacts.Phones.NUMBER_KEY); 439 440 sExtensionProjectionMap = new HashMap<String, String>(); 441 sExtensionProjectionMap.put(android.provider.Contacts.Extensions._ID, 442 android.provider.Contacts.Extensions._ID); 443 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.PERSON_ID, 444 android.provider.Contacts.Extensions.PERSON_ID); 445 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.NAME, 446 android.provider.Contacts.Extensions.NAME); 447 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.VALUE, 448 android.provider.Contacts.Extensions.VALUE); 449 450 sGroupProjectionMap = new HashMap<String, String>(); 451 sGroupProjectionMap.put(android.provider.Contacts.Groups._ID, 452 android.provider.Contacts.Groups._ID); 453 sGroupProjectionMap.put(android.provider.Contacts.Groups.NAME, 454 android.provider.Contacts.Groups.NAME); 455 sGroupProjectionMap.put(android.provider.Contacts.Groups.NOTES, 456 android.provider.Contacts.Groups.NOTES); 457 sGroupProjectionMap.put(android.provider.Contacts.Groups.SYSTEM_ID, 458 android.provider.Contacts.Groups.SYSTEM_ID); 459 460 sGroupMembershipProjectionMap = new HashMap<String, String>(sGroupProjectionMap); 461 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership._ID, 462 android.provider.Contacts.GroupMembership._ID); 463 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership.PERSON_ID, 464 android.provider.Contacts.GroupMembership.PERSON_ID); 465 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership.GROUP_ID, 466 android.provider.Contacts.GroupMembership.GROUP_ID); 467 sGroupMembershipProjectionMap.put( 468 android.provider.Contacts.GroupMembership.GROUP_SYNC_ID, 469 android.provider.Contacts.GroupMembership.GROUP_SYNC_ID); 470 sGroupMembershipProjectionMap.put( 471 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT, 472 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT); 473 sGroupMembershipProjectionMap.put( 474 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT_TYPE, 475 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT_TYPE); 476 477 sPhotoProjectionMap = new HashMap<String, String>(); 478 sPhotoProjectionMap.put(android.provider.Contacts.Photos._ID, 479 android.provider.Contacts.Photos._ID); 480 sPhotoProjectionMap.put(android.provider.Contacts.Photos.PERSON_ID, 481 android.provider.Contacts.Photos.PERSON_ID); 482 sPhotoProjectionMap.put(android.provider.Contacts.Photos.DATA, 483 android.provider.Contacts.Photos.DATA); 484 sPhotoProjectionMap.put(android.provider.Contacts.Photos.LOCAL_VERSION, 485 android.provider.Contacts.Photos.LOCAL_VERSION); 486 sPhotoProjectionMap.put(android.provider.Contacts.Photos.DOWNLOAD_REQUIRED, 487 android.provider.Contacts.Photos.DOWNLOAD_REQUIRED); 488 sPhotoProjectionMap.put(android.provider.Contacts.Photos.EXISTS_ON_SERVER, 489 android.provider.Contacts.Photos.EXISTS_ON_SERVER); 490 sPhotoProjectionMap.put(android.provider.Contacts.Photos.SYNC_ERROR, 491 android.provider.Contacts.Photos.SYNC_ERROR); 492 } 493 494 private final Context mContext; 495 private final ContactsDatabaseHelper mDbHelper; 496 private final ContactsProvider2 mContactsProvider; 497 private final NameSplitter mPhoneticNameSplitter; 498 private final GlobalSearchSupport mGlobalSearchSupport; 499 500 private final SQLiteStatement mDataMimetypeQuery; 501 private final SQLiteStatement mDataRawContactIdQuery; 502 503 private final ContentValues mValues = new ContentValues(); 504 private final ContentValues mValues2 = new ContentValues(); 505 private final ContentValues mValues3 = new ContentValues(); 506 private boolean mDefaultAccountKnown; 507 private Account mAccount; 508 509 private long mMimetypeEmail; 510 private long mMimetypeIm; 511 private long mMimetypePostal; 512 513 514 public LegacyApiSupport(Context context, ContactsDatabaseHelper contactsDatabaseHelper, 515 ContactsProvider2 contactsProvider, GlobalSearchSupport globalSearchSupport) { 516 mContext = context; 517 mContactsProvider = contactsProvider; 518 mDbHelper = contactsDatabaseHelper; 519 mGlobalSearchSupport = globalSearchSupport; 520 521 mPhoneticNameSplitter = new NameSplitter("", "", "", context 522 .getString(com.android.internal.R.string.common_name_conjunctions), Locale 523 .getDefault()); 524 525 SQLiteDatabase db = mDbHelper.getReadableDatabase(); 526 mDataMimetypeQuery = db.compileStatement( 527 "SELECT " + DataColumns.MIMETYPE_ID + 528 " FROM " + Tables.DATA + 529 " WHERE " + Data._ID + "=?"); 530 531 mDataRawContactIdQuery = db.compileStatement( 532 "SELECT " + Data.RAW_CONTACT_ID + 533 " FROM " + Tables.DATA + 534 " WHERE " + Data._ID + "=?"); 535 536 mMimetypeEmail = mDbHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE); 537 mMimetypeIm = mDbHelper.getMimeTypeId(Im.CONTENT_ITEM_TYPE); 538 mMimetypePostal = mDbHelper.getMimeTypeId(StructuredPostal.CONTENT_ITEM_TYPE); 539 } 540 541 private void ensureDefaultAccount() { 542 if (!mDefaultAccountKnown) { 543 mAccount = mContactsProvider.getDefaultAccount(); 544 mDefaultAccountKnown = true; 545 } 546 } 547 548 public static void createDatabase(SQLiteDatabase db) { 549 Log.i(TAG, "Bootstrapping database legacy support"); 550 createViews(db); 551 createSettingsTable(db); 552 } 553 554 public static void createViews(SQLiteDatabase db) { 555 556 String peopleColumns = "name." + StructuredName.DISPLAY_NAME 557 + " AS " + People.NAME + ", " + 558 Tables.RAW_CONTACTS + "." + RawContactsColumns.DISPLAY_NAME 559 + " AS " + People.DISPLAY_NAME + ", " + 560 PHONETIC_NAME_SQL 561 + " AS " + People.PHONETIC_NAME + " , " + 562 "note." + Note.NOTE 563 + " AS " + People.NOTES + ", " + 564 RawContacts.ACCOUNT_NAME + ", " + 565 RawContacts.ACCOUNT_TYPE + ", " + 566 Tables.RAW_CONTACTS + "." + RawContacts.TIMES_CONTACTED 567 + " AS " + People.TIMES_CONTACTED + ", " + 568 Tables.RAW_CONTACTS + "." + RawContacts.LAST_TIME_CONTACTED 569 + " AS " + People.LAST_TIME_CONTACTED + ", " + 570 Tables.RAW_CONTACTS + "." + RawContacts.CUSTOM_RINGTONE 571 + " AS " + People.CUSTOM_RINGTONE + ", " + 572 Tables.RAW_CONTACTS + "." + RawContacts.SEND_TO_VOICEMAIL 573 + " AS " + People.SEND_TO_VOICEMAIL + ", " + 574 Tables.RAW_CONTACTS + "." + RawContacts.STARRED 575 + " AS " + People.STARRED + ", " + 576 "organization." + Data._ID 577 + " AS " + People.PRIMARY_ORGANIZATION_ID + ", " + 578 "email." + Data._ID 579 + " AS " + People.PRIMARY_EMAIL_ID + ", " + 580 "phone." + Data._ID 581 + " AS " + People.PRIMARY_PHONE_ID + ", " + 582 "phone." + Phone.NUMBER 583 + " AS " + People.NUMBER + ", " + 584 "phone." + Phone.TYPE 585 + " AS " + People.TYPE + ", " + 586 "phone." + Phone.LABEL 587 + " AS " + People.LABEL + ", " + 588 "phone." + PhoneColumns.NORMALIZED_NUMBER 589 + " AS " + People.NUMBER_KEY; 590 591 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.PEOPLE + ";"); 592 db.execSQL("CREATE VIEW " + LegacyTables.PEOPLE + " AS SELECT " + 593 RawContactsColumns.CONCRETE_ID 594 + " AS " + android.provider.Contacts.People._ID + ", " + 595 peopleColumns + 596 " FROM " + Tables.RAW_CONTACTS + PEOPLE_JOINS + 597 " WHERE " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" + 598 " AND " + RawContacts.IS_RESTRICTED + "=0" + ";"); 599 600 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.ORGANIZATIONS + ";"); 601 db.execSQL("CREATE VIEW " + LegacyTables.ORGANIZATIONS + " AS SELECT " + 602 DataColumns.CONCRETE_ID 603 + " AS " + android.provider.Contacts.Organizations._ID + ", " + 604 Data.RAW_CONTACT_ID 605 + " AS " + android.provider.Contacts.Organizations.PERSON_ID + ", " + 606 Data.IS_PRIMARY 607 + " AS " + android.provider.Contacts.Organizations.ISPRIMARY + ", " + 608 RawContacts.ACCOUNT_NAME + ", " + 609 RawContacts.ACCOUNT_TYPE + ", " + 610 Organization.COMPANY 611 + " AS " + android.provider.Contacts.Organizations.COMPANY + ", " + 612 Organization.TYPE 613 + " AS " + android.provider.Contacts.Organizations.TYPE + ", " + 614 Organization.LABEL 615 + " AS " + android.provider.Contacts.Organizations.LABEL + ", " + 616 Organization.TITLE 617 + " AS " + android.provider.Contacts.Organizations.TITLE + 618 " FROM " + Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS + 619 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 620 + Organization.CONTENT_ITEM_TYPE + "'" 621 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" 622 + " AND " + RawContacts.IS_RESTRICTED + "=0" + 623 ";"); 624 625 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.CONTACT_METHODS + ";"); 626 db.execSQL("CREATE VIEW " + LegacyTables.CONTACT_METHODS + " AS SELECT " + 627 DataColumns.CONCRETE_ID 628 + " AS " + ContactMethods._ID + ", " + 629 DataColumns.CONCRETE_RAW_CONTACT_ID 630 + " AS " + ContactMethods.PERSON_ID + ", " + 631 CONTACT_METHOD_KIND_SQL 632 + " AS " + ContactMethods.KIND + ", " + 633 DataColumns.CONCRETE_IS_PRIMARY 634 + " AS " + ContactMethods.ISPRIMARY + ", " + 635 Tables.DATA + "." + Email.TYPE 636 + " AS " + ContactMethods.TYPE + ", " + 637 CONTACT_METHOD_DATA_SQL 638 + " AS " + ContactMethods.DATA + ", " + 639 Tables.DATA + "." + Email.LABEL 640 + " AS " + ContactMethods.LABEL + ", " + 641 DataColumns.CONCRETE_DATA14 642 + " AS " + ContactMethods.AUX_DATA + ", " + 643 peopleColumns + 644 " FROM " + Tables.DATA + DATA_JOINS + 645 " WHERE " + ContactMethods.KIND + " IS NOT NULL" 646 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" 647 + " AND " + RawContacts.IS_RESTRICTED + "=0" + 648 ";"); 649 650 651 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.PHONES + ";"); 652 db.execSQL("CREATE VIEW " + LegacyTables.PHONES + " AS SELECT " + 653 DataColumns.CONCRETE_ID 654 + " AS " + android.provider.Contacts.Phones._ID + ", " + 655 DataColumns.CONCRETE_RAW_CONTACT_ID 656 + " AS " + android.provider.Contacts.Phones.PERSON_ID + ", " + 657 DataColumns.CONCRETE_IS_PRIMARY 658 + " AS " + android.provider.Contacts.Phones.ISPRIMARY + ", " + 659 Tables.DATA + "." + Phone.NUMBER 660 + " AS " + android.provider.Contacts.Phones.NUMBER + ", " + 661 Tables.DATA + "." + Phone.TYPE 662 + " AS " + android.provider.Contacts.Phones.TYPE + ", " + 663 Tables.DATA + "." + Phone.LABEL 664 + " AS " + android.provider.Contacts.Phones.LABEL + ", " + 665 Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.NORMALIZED_NUMBER 666 + " AS " + android.provider.Contacts.Phones.NUMBER_KEY + ", " + 667 peopleColumns + 668 " FROM " + Tables.DATA 669 + " JOIN " + Tables.PHONE_LOOKUP 670 + " ON (" + Tables.DATA + "._id = " 671 + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.DATA_ID + ")" 672 + DATA_JOINS + 673 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 674 + Phone.CONTENT_ITEM_TYPE + "'" 675 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" 676 + " AND " + RawContacts.IS_RESTRICTED + "=0" + 677 ";"); 678 679 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.EXTENSIONS + ";"); 680 db.execSQL("CREATE VIEW " + LegacyTables.EXTENSIONS + " AS SELECT " + 681 DataColumns.CONCRETE_ID 682 + " AS " + android.provider.Contacts.Extensions._ID + ", " + 683 DataColumns.CONCRETE_RAW_CONTACT_ID 684 + " AS " + android.provider.Contacts.Extensions.PERSON_ID + ", " + 685 RawContacts.ACCOUNT_NAME + ", " + 686 RawContacts.ACCOUNT_TYPE + ", " + 687 ExtensionsColumns.NAME 688 + " AS " + android.provider.Contacts.Extensions.NAME + ", " + 689 ExtensionsColumns.VALUE 690 + " AS " + android.provider.Contacts.Extensions.VALUE + 691 " FROM " + Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS + 692 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 693 + android.provider.Contacts.Extensions.CONTENT_ITEM_TYPE + "'" 694 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" 695 + " AND " + RawContacts.IS_RESTRICTED + "=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 Groups.ACCOUNT_NAME + ", " + 702 Groups.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 ";"); 708 709 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.GROUP_MEMBERSHIP + ";"); 710 db.execSQL("CREATE VIEW " + LegacyTables.GROUP_MEMBERSHIP + " AS SELECT " + 711 DataColumns.CONCRETE_ID 712 + " AS " + android.provider.Contacts.GroupMembership._ID + ", " + 713 DataColumns.CONCRETE_RAW_CONTACT_ID 714 + " AS " + android.provider.Contacts.GroupMembership.PERSON_ID + ", " + 715 Tables.RAW_CONTACTS + "." + RawContacts.ACCOUNT_NAME 716 + " AS " + RawContacts.ACCOUNT_NAME + ", " + 717 Tables.RAW_CONTACTS + "." + RawContacts.ACCOUNT_TYPE 718 + " AS " + RawContacts.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 GroupsColumns.CONCRETE_ACCOUNT_NAME 731 + " AS " 732 + android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT + ", " + 733 GroupsColumns.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 RawContacts.ACCOUNT_NAME + ", " + 749 RawContacts.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 + " AND " + RawContacts.IS_RESTRICTED + "=0" + 765 ";"); 766 767 } 768 769 public static void createSettingsTable(SQLiteDatabase db) { 770 db.execSQL("DROP TABLE IF EXISTS " + LegacyTables.SETTINGS + ";"); 771 db.execSQL("CREATE TABLE " + LegacyTables.SETTINGS + " (" + 772 android.provider.Contacts.Settings._ID + " INTEGER PRIMARY KEY," + 773 android.provider.Contacts.Settings._SYNC_ACCOUNT + " TEXT," + 774 android.provider.Contacts.Settings._SYNC_ACCOUNT_TYPE + " TEXT," + 775 android.provider.Contacts.Settings.KEY + " STRING NOT NULL," + 776 android.provider.Contacts.Settings.VALUE + " STRING " + 777 ");"); 778 } 779 780 public Uri insert(Uri uri, ContentValues values) { 781 ensureDefaultAccount(); 782 final int match = sUriMatcher.match(uri); 783 long id = 0; 784 switch (match) { 785 case PEOPLE: 786 id = insertPeople(values); 787 break; 788 789 case ORGANIZATIONS: 790 id = insertOrganization(values); 791 break; 792 793 case PEOPLE_CONTACTMETHODS: { 794 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 795 id = insertContactMethod(rawContactId, values); 796 break; 797 } 798 799 case CONTACTMETHODS: { 800 long rawContactId = getRequiredValue(values, ContactMethods.PERSON_ID); 801 id = insertContactMethod(rawContactId, values); 802 break; 803 } 804 805 case PHONES: { 806 long rawContactId = getRequiredValue(values, 807 android.provider.Contacts.Phones.PERSON_ID); 808 id = insertPhone(rawContactId, values); 809 break; 810 } 811 812 case PEOPLE_PHONES: { 813 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 814 id = insertPhone(rawContactId, values); 815 break; 816 } 817 818 case EXTENSIONS: { 819 long rawContactId = getRequiredValue(values, 820 android.provider.Contacts.Extensions.PERSON_ID); 821 id = insertExtension(rawContactId, values); 822 break; 823 } 824 825 case GROUPS: 826 id = insertGroup(values); 827 break; 828 829 case GROUPMEMBERSHIP: { 830 long rawContactId = getRequiredValue(values, 831 android.provider.Contacts.GroupMembership.PERSON_ID); 832 long groupId = getRequiredValue(values, 833 android.provider.Contacts.GroupMembership.GROUP_ID); 834 id = insertGroupMembership(rawContactId, groupId); 835 break; 836 } 837 838 default: 839 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 840 } 841 842 if (id < 0) { 843 return null; 844 } 845 846 final Uri result = ContentUris.withAppendedId(uri, id); 847 onChange(result); 848 return result; 849 } 850 851 private long getRequiredValue(ContentValues values, String column) { 852 if (!values.containsKey(column)) { 853 throw new RuntimeException("Required value: " + column); 854 } 855 856 return values.getAsLong(column); 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.update(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.update(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.update(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 long lastTimeContacted; 1154 if (values.containsKey(People.LAST_TIME_CONTACTED)) { 1155 lastTimeContacted = values.getAsLong(People.LAST_TIME_CONTACTED); 1156 } else { 1157 lastTimeContacted = System.currentTimeMillis(); 1158 } 1159 1160 // TODO check sanctions 1161 long contactId = mDbHelper.getContactId(rawContactId); 1162 SQLiteDatabase mDb = mDbHelper.getWritableDatabase(); 1163 mSelectionArgs2[0] = String.valueOf(lastTimeContacted); 1164 if (contactId != 0) { 1165 mSelectionArgs2[1] = String.valueOf(contactId); 1166 mDb.execSQL(CONTACTS_UPDATE_LASTTIMECONTACTED, mSelectionArgs2); 1167 // increment times_contacted column 1168 mSelectionArgs1[0] = String.valueOf(contactId); 1169 mDb.execSQL(ContactsProvider2.UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 1170 } 1171 mSelectionArgs2[1] = String.valueOf(rawContactId); 1172 mDb.execSQL(RAWCONTACTS_UPDATE_LASTTIMECONTACTED, mSelectionArgs2); 1173 // increment times_contacted column 1174 mSelectionArgs1[0] = String.valueOf(contactId); 1175 mDb.execSQL(ContactsProvider2.UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 1176 } 1177 1178 private int updatePhoto(long rawContactId, ContentValues values) { 1179 1180 // TODO check sanctions 1181 1182 int count; 1183 1184 long dataId = findFirstDataId(rawContactId, Photo.CONTENT_ITEM_TYPE); 1185 1186 mValues.clear(); 1187 byte[] bytes = values.getAsByteArray(android.provider.Contacts.Photos.DATA); 1188 mValues.put(Photo.PHOTO, bytes); 1189 1190 if (dataId == -1) { 1191 mValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 1192 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 1193 Uri dataUri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 1194 dataId = ContentUris.parseId(dataUri); 1195 count = 1; 1196 } else { 1197 Uri dataUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId); 1198 count = mContactsProvider.updateInTransaction(dataUri, mValues, null, null); 1199 } 1200 1201 updateLegacyPhotoData(rawContactId, dataId, values); 1202 1203 return count; 1204 } 1205 1206 private int updatePhotoByDataId(long dataId, ContentValues values) { 1207 1208 mDataRawContactIdQuery.bindLong(1, dataId); 1209 long rawContactId; 1210 1211 try { 1212 rawContactId = mDataRawContactIdQuery.simpleQueryForLong(); 1213 } catch (SQLiteDoneException e) { 1214 // Data row not found 1215 return 0; 1216 } 1217 1218 if (values.containsKey(android.provider.Contacts.Photos.DATA)) { 1219 byte[] bytes = values.getAsByteArray(android.provider.Contacts.Photos.DATA); 1220 mValues.clear(); 1221 mValues.put(Photo.PHOTO, bytes); 1222 mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1223 Data._ID + "=" + dataId, null); 1224 } 1225 1226 updateLegacyPhotoData(rawContactId, dataId, values); 1227 1228 return 1; 1229 } 1230 1231 private void updateLegacyPhotoData(long rawContactId, long dataId, ContentValues values) { 1232 mValues.clear(); 1233 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.LOCAL_VERSION, 1234 values, android.provider.Contacts.Photos.LOCAL_VERSION); 1235 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.DOWNLOAD_REQUIRED, 1236 values, android.provider.Contacts.Photos.DOWNLOAD_REQUIRED); 1237 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.EXISTS_ON_SERVER, 1238 values, android.provider.Contacts.Photos.EXISTS_ON_SERVER); 1239 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.SYNC_ERROR, 1240 values, android.provider.Contacts.Photos.SYNC_ERROR); 1241 1242 int updated = mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1243 Data.MIMETYPE + "='" + LegacyPhotoData.CONTENT_ITEM_TYPE + "'" 1244 + " AND " + Data.RAW_CONTACT_ID + "=" + rawContactId 1245 + " AND " + LegacyPhotoData.PHOTO_DATA_ID + "=" + dataId, null); 1246 if (updated == 0) { 1247 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 1248 mValues.put(Data.MIMETYPE, LegacyPhotoData.CONTENT_ITEM_TYPE); 1249 mValues.put(LegacyPhotoData.PHOTO_DATA_ID, dataId); 1250 mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 1251 } 1252 } 1253 1254 private int updateSettings(ContentValues values) { 1255 SQLiteDatabase db = mDbHelper.getWritableDatabase(); 1256 String accountName = values.getAsString(android.provider.Contacts.Settings._SYNC_ACCOUNT); 1257 String accountType = 1258 values.getAsString(android.provider.Contacts.Settings._SYNC_ACCOUNT_TYPE); 1259 String key = values.getAsString(android.provider.Contacts.Settings.KEY); 1260 if (key == null) { 1261 throw new IllegalArgumentException("you must specify the key when updating settings"); 1262 } 1263 updateSetting(db, accountName, accountType, values); 1264 if (key.equals(android.provider.Contacts.Settings.SYNC_EVERYTHING)) { 1265 mValues.clear(); 1266 mValues.put(Settings.SHOULD_SYNC, 1267 values.getAsInteger(android.provider.Contacts.Settings.VALUE)); 1268 String selection; 1269 String[] selectionArgs; 1270 if (accountName != null && accountType != null) { 1271 selectionArgs = new String[]{accountName, accountType}; 1272 selection = Settings.ACCOUNT_NAME + "=?" 1273 + " AND " + Settings.ACCOUNT_TYPE + "=?"; 1274 } else { 1275 selectionArgs = null; 1276 selection = Settings.ACCOUNT_NAME + " IS NULL" 1277 + " AND " + Settings.ACCOUNT_TYPE + " 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 " + android.provider.Contacts.Settings.KEY + "='" 1318 + android.provider.Contacts.Settings.SYNC_EVERYTHING + "'" + 1319 ")" + 1320 " WHERE " + ContactsContract.Settings.SHOULD_SYNC + "<>" 1321 + android.provider.Contacts.Settings.VALUE; 1322 1323 int ACCOUNT_NAME = 0; 1324 int ACCOUNT_TYPE = 1; 1325 int SHOULD_SYNC = 2; 1326 } 1327 1328 /** 1329 * Brings legacy settings table in sync with the new settings. 1330 */ 1331 public void copySettingsToLegacySettings() { 1332 SQLiteDatabase db = mDbHelper.getWritableDatabase(); 1333 Cursor cursor = db.rawQuery(SettingsMatchQuery.SQL, null); 1334 try { 1335 while(cursor.moveToNext()) { 1336 String accountName = cursor.getString(SettingsMatchQuery.ACCOUNT_NAME); 1337 String accountType = cursor.getString(SettingsMatchQuery.ACCOUNT_TYPE); 1338 String value = cursor.getString(SettingsMatchQuery.SHOULD_SYNC); 1339 mValues.clear(); 1340 mValues.put(android.provider.Contacts.Settings._SYNC_ACCOUNT, accountName); 1341 mValues.put(android.provider.Contacts.Settings._SYNC_ACCOUNT_TYPE, accountType); 1342 mValues.put(android.provider.Contacts.Settings.KEY, 1343 android.provider.Contacts.Settings.SYNC_EVERYTHING); 1344 mValues.put(android.provider.Contacts.Settings.VALUE, value); 1345 updateSetting(db, accountName, accountType, mValues); 1346 } 1347 } finally { 1348 cursor.close(); 1349 } 1350 } 1351 1352 private void parsePeopleValues(ContentValues values) { 1353 mValues.clear(); 1354 mValues2.clear(); 1355 mValues3.clear(); 1356 1357 ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 1358 values, People.CUSTOM_RINGTONE); 1359 ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 1360 values, People.SEND_TO_VOICEMAIL); 1361 ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 1362 values, People.LAST_TIME_CONTACTED); 1363 ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 1364 values, People.TIMES_CONTACTED); 1365 ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 1366 values, People.STARRED); 1367 if (mAccount != null) { 1368 mValues.put(RawContacts.ACCOUNT_NAME, mAccount.name); 1369 mValues.put(RawContacts.ACCOUNT_TYPE, mAccount.type); 1370 } 1371 1372 if (values.containsKey(People.NAME) || values.containsKey(People.PHONETIC_NAME)) { 1373 mValues2.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 1374 ContactsDatabaseHelper.copyStringValue(mValues2, StructuredName.DISPLAY_NAME, 1375 values, People.NAME); 1376 if (values.containsKey(People.PHONETIC_NAME)) { 1377 String phoneticName = values.getAsString(People.PHONETIC_NAME); 1378 NameSplitter.Name parsedName = new NameSplitter.Name(); 1379 mPhoneticNameSplitter.split(parsedName, phoneticName); 1380 mValues2.put(StructuredName.PHONETIC_GIVEN_NAME, parsedName.getGivenNames()); 1381 mValues2.put(StructuredName.PHONETIC_MIDDLE_NAME, parsedName.getMiddleName()); 1382 mValues2.put(StructuredName.PHONETIC_FAMILY_NAME, parsedName.getFamilyName()); 1383 } 1384 } 1385 1386 if (values.containsKey(People.NOTES)) { 1387 mValues3.put(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE); 1388 ContactsDatabaseHelper.copyStringValue(mValues3, Note.NOTE, values, People.NOTES); 1389 } 1390 } 1391 1392 private void parseOrganizationValues(ContentValues values) { 1393 mValues.clear(); 1394 1395 mValues.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE); 1396 1397 ContactsDatabaseHelper.copyLongValue(mValues, Data.IS_PRIMARY, 1398 values, android.provider.Contacts.Organizations.ISPRIMARY); 1399 1400 ContactsDatabaseHelper.copyStringValue(mValues, Organization.COMPANY, 1401 values, android.provider.Contacts.Organizations.COMPANY); 1402 1403 // TYPE values happen to remain the same between V1 and V2 - can just copy the value 1404 ContactsDatabaseHelper.copyLongValue(mValues, Organization.TYPE, 1405 values, android.provider.Contacts.Organizations.TYPE); 1406 1407 ContactsDatabaseHelper.copyStringValue(mValues, Organization.LABEL, 1408 values, android.provider.Contacts.Organizations.LABEL); 1409 ContactsDatabaseHelper.copyStringValue(mValues, Organization.TITLE, 1410 values, android.provider.Contacts.Organizations.TITLE); 1411 } 1412 1413 private void parsePhoneValues(ContentValues values) { 1414 mValues.clear(); 1415 1416 mValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1417 1418 ContactsDatabaseHelper.copyLongValue(mValues, Data.IS_PRIMARY, 1419 values, android.provider.Contacts.Phones.ISPRIMARY); 1420 1421 ContactsDatabaseHelper.copyStringValue(mValues, Phone.NUMBER, 1422 values, android.provider.Contacts.Phones.NUMBER); 1423 1424 // TYPE values happen to remain the same between V1 and V2 - can just copy the value 1425 ContactsDatabaseHelper.copyLongValue(mValues, Phone.TYPE, 1426 values, android.provider.Contacts.Phones.TYPE); 1427 1428 ContactsDatabaseHelper.copyStringValue(mValues, Phone.LABEL, 1429 values, android.provider.Contacts.Phones.LABEL); 1430 } 1431 1432 private void parseContactMethodValues(int kind, ContentValues values) { 1433 mValues.clear(); 1434 1435 ContactsDatabaseHelper.copyLongValue(mValues, Data.IS_PRIMARY, values, 1436 ContactMethods.ISPRIMARY); 1437 1438 switch (kind) { 1439 case android.provider.Contacts.KIND_EMAIL: { 1440 copyCommonFields(values, Email.CONTENT_ITEM_TYPE, Email.TYPE, Email.LABEL, 1441 Data.DATA14); 1442 ContactsDatabaseHelper.copyStringValue(mValues, Email.DATA, values, 1443 ContactMethods.DATA); 1444 break; 1445 } 1446 1447 case android.provider.Contacts.KIND_IM: { 1448 String protocol = values.getAsString(ContactMethods.DATA); 1449 if (protocol.startsWith("pre:")) { 1450 mValues.put(Im.PROTOCOL, Integer.parseInt(protocol.substring(4))); 1451 } else if (protocol.startsWith("custom:")) { 1452 mValues.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM); 1453 mValues.put(Im.CUSTOM_PROTOCOL, protocol.substring(7)); 1454 } 1455 1456 copyCommonFields(values, Im.CONTENT_ITEM_TYPE, Im.TYPE, Im.LABEL, Data.DATA14); 1457 break; 1458 } 1459 1460 case android.provider.Contacts.KIND_POSTAL: { 1461 copyCommonFields(values, StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, 1462 StructuredPostal.LABEL, Data.DATA14); 1463 ContactsDatabaseHelper.copyStringValue(mValues, StructuredPostal.FORMATTED_ADDRESS, 1464 values, ContactMethods.DATA); 1465 break; 1466 } 1467 } 1468 } 1469 1470 private void copyCommonFields(ContentValues values, String mimeType, String typeColumn, 1471 String labelColumn, String auxDataColumn) { 1472 mValues.put(Data.MIMETYPE, mimeType); 1473 ContactsDatabaseHelper.copyLongValue(mValues, typeColumn, values, 1474 ContactMethods.TYPE); 1475 ContactsDatabaseHelper.copyStringValue(mValues, labelColumn, values, 1476 ContactMethods.LABEL); 1477 ContactsDatabaseHelper.copyStringValue(mValues, auxDataColumn, values, 1478 ContactMethods.AUX_DATA); 1479 } 1480 1481 private void parseGroupValues(ContentValues values) { 1482 mValues.clear(); 1483 1484 ContactsDatabaseHelper.copyStringValue(mValues, Groups.TITLE, 1485 values, android.provider.Contacts.Groups.NAME); 1486 ContactsDatabaseHelper.copyStringValue(mValues, Groups.NOTES, 1487 values, android.provider.Contacts.Groups.NOTES); 1488 ContactsDatabaseHelper.copyStringValue(mValues, Groups.SYSTEM_ID, 1489 values, android.provider.Contacts.Groups.SYSTEM_ID); 1490 } 1491 1492 private void parseExtensionValues(ContentValues values) { 1493 ContactsDatabaseHelper.copyStringValue(mValues, ExtensionsColumns.NAME, 1494 values, android.provider.Contacts.People.Extensions.NAME); 1495 ContactsDatabaseHelper.copyStringValue(mValues, ExtensionsColumns.VALUE, 1496 values, android.provider.Contacts.People.Extensions.VALUE); 1497 } 1498 1499 private Uri findFirstDataRow(long rawContactId, String contentItemType) { 1500 long dataId = findFirstDataId(rawContactId, contentItemType); 1501 if (dataId == -1) { 1502 return null; 1503 } 1504 1505 return ContentUris.withAppendedId(Data.CONTENT_URI, dataId); 1506 } 1507 1508 private long findFirstDataId(long rawContactId, String mimeType) { 1509 long dataId = -1; 1510 Cursor c = mContactsProvider.query(Data.CONTENT_URI, IdQuery.COLUMNS, 1511 Data.RAW_CONTACT_ID + "=" + rawContactId + " AND " 1512 + Data.MIMETYPE + "='" + mimeType + "'", 1513 null, null); 1514 try { 1515 if (c.moveToFirst()) { 1516 dataId = c.getLong(IdQuery._ID); 1517 } 1518 } finally { 1519 c.close(); 1520 } 1521 return dataId; 1522 } 1523 1524 1525 public int delete(Uri uri, String selection, String[] selectionArgs) { 1526 final int match = sUriMatcher.match(uri); 1527 if (match == -1 || match == SETTINGS) { 1528 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 1529 } 1530 1531 Cursor c = query(uri, IdQuery.COLUMNS, selection, selectionArgs, null, null); 1532 if (c == null) { 1533 return 0; 1534 } 1535 1536 int count = 0; 1537 try { 1538 while (c.moveToNext()) { 1539 long id = c.getLong(IdQuery._ID); 1540 count += delete(uri, match, id); 1541 } 1542 } finally { 1543 c.close(); 1544 } 1545 1546 return count; 1547 } 1548 1549 public int delete(Uri uri, int match, long id) { 1550 int count = 0; 1551 switch (match) { 1552 case PEOPLE: 1553 case PEOPLE_ID: 1554 count = mContactsProvider.deleteRawContact(id, mDbHelper.getContactId(id), false); 1555 break; 1556 1557 case PEOPLE_PHOTO: 1558 mValues.clear(); 1559 mValues.putNull(android.provider.Contacts.Photos.DATA); 1560 updatePhoto(id, mValues); 1561 break; 1562 1563 case ORGANIZATIONS: 1564 case ORGANIZATIONS_ID: 1565 count = mContactsProvider.deleteData(id, ORGANIZATION_MIME_TYPES); 1566 break; 1567 1568 case CONTACTMETHODS: 1569 case CONTACTMETHODS_ID: 1570 count = mContactsProvider.deleteData(id, CONTACT_METHOD_MIME_TYPES); 1571 break; 1572 1573 case PHONES: 1574 case PHONES_ID: 1575 count = mContactsProvider.deleteData(id, PHONE_MIME_TYPES); 1576 break; 1577 1578 case EXTENSIONS: 1579 case EXTENSIONS_ID: 1580 count = mContactsProvider.deleteData(id, EXTENSION_MIME_TYPES); 1581 break; 1582 1583 case PHOTOS: 1584 case PHOTOS_ID: 1585 count = mContactsProvider.deleteData(id, PHOTO_MIME_TYPES); 1586 break; 1587 1588 case GROUPMEMBERSHIP: 1589 case GROUPMEMBERSHIP_ID: 1590 count = mContactsProvider.deleteData(id, GROUP_MEMBERSHIP_MIME_TYPES); 1591 break; 1592 1593 case GROUPS: 1594 case GROUPS_ID: 1595 count = mContactsProvider.deleteGroup(uri, id, false); 1596 break; 1597 1598 default: 1599 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 1600 } 1601 1602 return count; 1603 } 1604 1605 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 1606 String sortOrder, String limit) { 1607 ensureDefaultAccount(); 1608 1609 final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 1610 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 1611 String groupBy = null; 1612 1613 final int match = sUriMatcher.match(uri); 1614 switch (match) { 1615 case PEOPLE: { 1616 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1617 qb.setProjectionMap(sPeopleProjectionMap); 1618 applyRawContactsAccount(qb); 1619 break; 1620 } 1621 1622 case PEOPLE_ID: 1623 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1624 qb.setProjectionMap(sPeopleProjectionMap); 1625 applyRawContactsAccount(qb); 1626 qb.appendWhere(" AND " + People._ID + "="); 1627 qb.appendWhere(uri.getPathSegments().get(1)); 1628 break; 1629 1630 case PEOPLE_FILTER: { 1631 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1632 qb.setProjectionMap(sPeopleProjectionMap); 1633 applyRawContactsAccount(qb); 1634 String filterParam = uri.getPathSegments().get(2); 1635 qb.appendWhere(" AND " + People._ID + " IN " 1636 + mContactsProvider.getRawContactsByFilterAsNestedQuery(filterParam)); 1637 break; 1638 } 1639 1640 case GROUP_NAME_MEMBERS: 1641 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1642 qb.setProjectionMap(sPeopleProjectionMap); 1643 applyRawContactsAccount(qb); 1644 String group = uri.getPathSegments().get(2); 1645 qb.appendWhere(" AND " + buildGroupNameMatchWhereClause(group)); 1646 break; 1647 1648 case GROUP_SYSTEM_ID_MEMBERS: 1649 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1650 qb.setProjectionMap(sPeopleProjectionMap); 1651 applyRawContactsAccount(qb); 1652 String systemId = uri.getPathSegments().get(2); 1653 qb.appendWhere(" AND " + buildGroupSystemIdMatchWhereClause(systemId)); 1654 break; 1655 1656 case ORGANIZATIONS: 1657 qb.setTables(LegacyTables.ORGANIZATIONS + " organizations"); 1658 qb.setProjectionMap(sOrganizationProjectionMap); 1659 applyRawContactsAccount(qb); 1660 break; 1661 1662 case ORGANIZATIONS_ID: 1663 qb.setTables(LegacyTables.ORGANIZATIONS + " organizations"); 1664 qb.setProjectionMap(sOrganizationProjectionMap); 1665 applyRawContactsAccount(qb); 1666 qb.appendWhere(" AND " + android.provider.Contacts.Organizations._ID + "="); 1667 qb.appendWhere(uri.getPathSegments().get(1)); 1668 break; 1669 1670 case PEOPLE_ORGANIZATIONS: 1671 qb.setTables(LegacyTables.ORGANIZATIONS + " organizations"); 1672 qb.setProjectionMap(sOrganizationProjectionMap); 1673 applyRawContactsAccount(qb); 1674 qb.appendWhere(" AND " + android.provider.Contacts.Organizations.PERSON_ID + "="); 1675 qb.appendWhere(uri.getPathSegments().get(1)); 1676 break; 1677 1678 case PEOPLE_ORGANIZATIONS_ID: 1679 qb.setTables(LegacyTables.ORGANIZATIONS + " organizations"); 1680 qb.setProjectionMap(sOrganizationProjectionMap); 1681 applyRawContactsAccount(qb); 1682 qb.appendWhere(" AND " + android.provider.Contacts.Organizations.PERSON_ID + "="); 1683 qb.appendWhere(uri.getPathSegments().get(1)); 1684 qb.appendWhere(" AND " + android.provider.Contacts.Organizations._ID + "="); 1685 qb.appendWhere(uri.getPathSegments().get(3)); 1686 break; 1687 1688 case CONTACTMETHODS: 1689 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1690 qb.setProjectionMap(sContactMethodProjectionMap); 1691 applyRawContactsAccount(qb); 1692 break; 1693 1694 case CONTACTMETHODS_ID: 1695 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1696 qb.setProjectionMap(sContactMethodProjectionMap); 1697 applyRawContactsAccount(qb); 1698 qb.appendWhere(" AND " + ContactMethods._ID + "="); 1699 qb.appendWhere(uri.getPathSegments().get(1)); 1700 break; 1701 1702 case CONTACTMETHODS_EMAIL: 1703 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1704 qb.setProjectionMap(sContactMethodProjectionMap); 1705 applyRawContactsAccount(qb); 1706 qb.appendWhere(" AND " + ContactMethods.KIND + "=" 1707 + android.provider.Contacts.KIND_EMAIL); 1708 break; 1709 1710 case PEOPLE_CONTACTMETHODS: 1711 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1712 qb.setProjectionMap(sContactMethodProjectionMap); 1713 applyRawContactsAccount(qb); 1714 qb.appendWhere(" AND " + ContactMethods.PERSON_ID + "="); 1715 qb.appendWhere(uri.getPathSegments().get(1)); 1716 qb.appendWhere(" AND " + ContactMethods.KIND + " IS NOT NULL"); 1717 break; 1718 1719 case PEOPLE_CONTACTMETHODS_ID: 1720 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1721 qb.setProjectionMap(sContactMethodProjectionMap); 1722 applyRawContactsAccount(qb); 1723 qb.appendWhere(" AND " + ContactMethods.PERSON_ID + "="); 1724 qb.appendWhere(uri.getPathSegments().get(1)); 1725 qb.appendWhere(" AND " + ContactMethods._ID + "="); 1726 qb.appendWhere(uri.getPathSegments().get(3)); 1727 qb.appendWhere(" AND " + ContactMethods.KIND + " IS NOT NULL"); 1728 break; 1729 1730 case PHONES: 1731 qb.setTables(LegacyTables.PHONES + " phones"); 1732 qb.setProjectionMap(sPhoneProjectionMap); 1733 applyRawContactsAccount(qb); 1734 break; 1735 1736 case PHONES_ID: 1737 qb.setTables(LegacyTables.PHONES + " phones"); 1738 qb.setProjectionMap(sPhoneProjectionMap); 1739 applyRawContactsAccount(qb); 1740 qb.appendWhere(" AND " + android.provider.Contacts.Phones._ID + "="); 1741 qb.appendWhere(uri.getPathSegments().get(1)); 1742 break; 1743 1744 case PHONES_FILTER: 1745 qb.setTables(LegacyTables.PHONES + " phones"); 1746 qb.setProjectionMap(sPhoneProjectionMap); 1747 applyRawContactsAccount(qb); 1748 if (uri.getPathSegments().size() > 2) { 1749 String filterParam = uri.getLastPathSegment(); 1750 qb.appendWhere(" AND person ="); 1751 qb.appendWhere(mDbHelper.buildPhoneLookupAsNestedQuery(filterParam)); 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 1876 // No legacy compatibility for search suggestions 1877 return mGlobalSearchSupport.handleSearchSuggestionsQuery(db, uri, limit); 1878 1879 case SEARCH_SHORTCUT: { 1880 String lookupKey = uri.getLastPathSegment(); 1881 return mGlobalSearchSupport.handleSearchShortcutRefresh(db, lookupKey, projection); 1882 } 1883 1884 case LIVE_FOLDERS_PEOPLE: 1885 return mContactsProvider.query(LIVE_FOLDERS_CONTACTS_URI, 1886 projection, selection, selectionArgs, sortOrder); 1887 1888 case LIVE_FOLDERS_PEOPLE_WITH_PHONES: 1889 return mContactsProvider.query(LIVE_FOLDERS_CONTACTS_WITH_PHONES_URI, 1890 projection, selection, selectionArgs, sortOrder); 1891 1892 case LIVE_FOLDERS_PEOPLE_FAVORITES: 1893 return mContactsProvider.query(LIVE_FOLDERS_CONTACTS_FAVORITES_URI, 1894 projection, selection, selectionArgs, sortOrder); 1895 1896 case LIVE_FOLDERS_PEOPLE_GROUP_NAME: 1897 return mContactsProvider.query(Uri.withAppendedPath(LIVE_FOLDERS_CONTACTS_URI, 1898 Uri.encode(uri.getLastPathSegment())), 1899 projection, selection, selectionArgs, sortOrder); 1900 1901 case DELETED_PEOPLE: 1902 case DELETED_GROUPS: 1903 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 1904 1905 case SETTINGS: 1906 copySettingsToLegacySettings(); 1907 qb.setTables(LegacyTables.SETTINGS); 1908 break; 1909 1910 default: 1911 throw new IllegalArgumentException(mDbHelper.exceptionMessage(uri)); 1912 } 1913 1914 // Perform the query and set the notification uri 1915 final Cursor c = qb.query(db, projection, selection, selectionArgs, 1916 groupBy, null, sortOrder, limit); 1917 if (c != null) { 1918 c.setNotificationUri(mContext.getContentResolver(), 1919 android.provider.Contacts.CONTENT_URI); 1920 } 1921 return c; 1922 } 1923 1924 private void applyRawContactsAccount(SQLiteQueryBuilder qb) { 1925 StringBuilder sb = new StringBuilder(); 1926 appendRawContactsAccount(sb); 1927 qb.appendWhere(sb.toString()); 1928 } 1929 1930 private void appendRawContactsAccount(StringBuilder sb) { 1931 if (mAccount != null) { 1932 sb.append(RawContacts.ACCOUNT_NAME + "="); 1933 DatabaseUtils.appendEscapedSQLString(sb, mAccount.name); 1934 sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 1935 DatabaseUtils.appendEscapedSQLString(sb, mAccount.type); 1936 } else { 1937 sb.append(RawContacts.ACCOUNT_NAME + " IS NULL" + 1938 " AND " + RawContacts.ACCOUNT_TYPE + " IS NULL"); 1939 } 1940 } 1941 1942 private void applyGroupAccount(SQLiteQueryBuilder qb) { 1943 StringBuilder sb = new StringBuilder(); 1944 appendGroupAccount(sb); 1945 qb.appendWhere(sb.toString()); 1946 } 1947 1948 private void appendGroupAccount(StringBuilder sb) { 1949 if (mAccount != null) { 1950 sb.append(Groups.ACCOUNT_NAME + "="); 1951 DatabaseUtils.appendEscapedSQLString(sb, mAccount.name); 1952 sb.append(" AND " + Groups.ACCOUNT_TYPE + "="); 1953 DatabaseUtils.appendEscapedSQLString(sb, mAccount.type); 1954 } else { 1955 sb.append(Groups.ACCOUNT_NAME + " IS NULL" + 1956 " AND " + Groups.ACCOUNT_TYPE + " IS NULL"); 1957 } 1958 } 1959 1960 /** 1961 * Build a WHERE clause that restricts the query to match people that are a member of 1962 * a group with a particular name. The projection map of the query must include 1963 * {@link People#_ID}. 1964 * 1965 * @param groupName The name of the group 1966 * @return The where clause. 1967 */ 1968 private String buildGroupNameMatchWhereClause(String groupName) { 1969 return "people._id IN " 1970 + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 1971 + " FROM " + Tables.DATA_JOIN_MIMETYPES 1972 + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE 1973 + "' AND " + GroupMembership.GROUP_ROW_ID + "=" 1974 + "(SELECT " + Tables.GROUPS + "." + Groups._ID 1975 + " FROM " + Tables.GROUPS 1976 + " WHERE " + Groups.TITLE + "=" 1977 + DatabaseUtils.sqlEscapeString(groupName) + "))"; 1978 } 1979 1980 /** 1981 * Build a WHERE clause that restricts the query to match people that are a member of 1982 * a group with a particular system id. The projection map of the query must include 1983 * {@link People#_ID}. 1984 * 1985 * @param groupName The name of the group 1986 * @return The where clause. 1987 */ 1988 private String buildGroupSystemIdMatchWhereClause(String systemId) { 1989 return "people._id IN " 1990 + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 1991 + " FROM " + Tables.DATA_JOIN_MIMETYPES 1992 + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE 1993 + "' AND " + GroupMembership.GROUP_ROW_ID + "=" 1994 + "(SELECT " + Tables.GROUPS + "." + Groups._ID 1995 + " FROM " + Tables.GROUPS 1996 + " WHERE " + Groups.SYSTEM_ID + "=" 1997 + DatabaseUtils.sqlEscapeString(systemId) + "))"; 1998 } 1999 2000 /** 2001 * Called when a change has been made. 2002 * 2003 * @param uri the uri that the change was made to 2004 */ 2005 private void onChange(Uri uri) { 2006 mContext.getContentResolver().notifyChange(android.provider.Contacts.CONTENT_URI, null); 2007 } 2008 2009 public String getType(Uri uri) { 2010 int match = sUriMatcher.match(uri); 2011 switch (match) { 2012 case EXTENSIONS: 2013 case PEOPLE_EXTENSIONS: 2014 return Extensions.CONTENT_TYPE; 2015 case EXTENSIONS_ID: 2016 case PEOPLE_EXTENSIONS_ID: 2017 return Extensions.CONTENT_ITEM_TYPE; 2018 case PEOPLE: 2019 return "vnd.android.cursor.dir/person"; 2020 case PEOPLE_ID: 2021 return "vnd.android.cursor.item/person"; 2022 case PEOPLE_PHONES: 2023 return "vnd.android.cursor.dir/phone"; 2024 case PEOPLE_PHONES_ID: 2025 return "vnd.android.cursor.item/phone"; 2026 case PEOPLE_CONTACTMETHODS: 2027 return "vnd.android.cursor.dir/contact-methods"; 2028 case PEOPLE_CONTACTMETHODS_ID: 2029 return getContactMethodType(uri); 2030 case PHONES: 2031 return "vnd.android.cursor.dir/phone"; 2032 case PHONES_ID: 2033 return "vnd.android.cursor.item/phone"; 2034 case PHONES_FILTER: 2035 return "vnd.android.cursor.dir/phone"; 2036 case PHOTOS_ID: 2037 return "vnd.android.cursor.item/photo"; 2038 case PHOTOS: 2039 return "vnd.android.cursor.dir/photo"; 2040 case PEOPLE_PHOTO: 2041 return "vnd.android.cursor.item/photo"; 2042 case CONTACTMETHODS: 2043 return "vnd.android.cursor.dir/contact-methods"; 2044 case CONTACTMETHODS_ID: 2045 return getContactMethodType(uri); 2046 case ORGANIZATIONS: 2047 return "vnd.android.cursor.dir/organizations"; 2048 case ORGANIZATIONS_ID: 2049 return "vnd.android.cursor.item/organization"; 2050 case SEARCH_SUGGESTIONS: 2051 return SearchManager.SUGGEST_MIME_TYPE; 2052 case SEARCH_SHORTCUT: 2053 return SearchManager.SHORTCUT_MIME_TYPE; 2054 default: 2055 throw new IllegalArgumentException(mDbHelper.exceptionMessage(uri)); 2056 } 2057 } 2058 2059 private String getContactMethodType(Uri url) { 2060 String mime = null; 2061 2062 Cursor c = query(url, new String[] {ContactMethods.KIND}, null, null, null, null); 2063 if (c != null) { 2064 try { 2065 if (c.moveToFirst()) { 2066 int kind = c.getInt(0); 2067 switch (kind) { 2068 case android.provider.Contacts.KIND_EMAIL: 2069 mime = "vnd.android.cursor.item/email"; 2070 break; 2071 2072 case android.provider.Contacts.KIND_IM: 2073 mime = "vnd.android.cursor.item/jabber-im"; 2074 break; 2075 2076 case android.provider.Contacts.KIND_POSTAL: 2077 mime = "vnd.android.cursor.item/postal-address"; 2078 break; 2079 } 2080 } 2081 } finally { 2082 c.close(); 2083 } 2084 } 2085 return mime; 2086 } 2087 } 2088