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.NameLookupColumns; 23import com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType; 24import com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns; 25import com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 26import com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; 27import com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns; 28import com.android.providers.contacts.ContactsDatabaseHelper.Tables; 29 30import android.accounts.Account; 31import android.app.SearchManager; 32import android.content.ContentUris; 33import android.content.ContentValues; 34import android.content.Context; 35import android.content.UriMatcher; 36import android.database.Cursor; 37import android.database.DatabaseUtils; 38import android.database.SQLException; 39import android.database.sqlite.SQLiteDatabase; 40import android.database.sqlite.SQLiteDoneException; 41import android.database.sqlite.SQLiteQueryBuilder; 42import android.database.sqlite.SQLiteStatement; 43import android.net.Uri; 44import android.provider.BaseColumns; 45import android.provider.Contacts.ContactMethods; 46import android.provider.Contacts.Extensions; 47import android.provider.Contacts.People; 48import android.provider.ContactsContract; 49import android.provider.ContactsContract.CommonDataKinds.Email; 50import android.provider.ContactsContract.CommonDataKinds.GroupMembership; 51import android.provider.ContactsContract.CommonDataKinds.Im; 52import android.provider.ContactsContract.CommonDataKinds.Note; 53import android.provider.ContactsContract.CommonDataKinds.Organization; 54import android.provider.ContactsContract.CommonDataKinds.Phone; 55import android.provider.ContactsContract.CommonDataKinds.Photo; 56import android.provider.ContactsContract.CommonDataKinds.StructuredName; 57import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 58import android.provider.ContactsContract.Contacts; 59import android.provider.ContactsContract.Data; 60import android.provider.ContactsContract.Groups; 61import android.provider.ContactsContract.RawContacts; 62import android.provider.ContactsContract.Settings; 63import android.provider.ContactsContract.StatusUpdates; 64import android.text.TextUtils; 65import android.util.Log; 66 67import java.util.HashMap; 68import java.util.Locale; 69 70@SuppressWarnings("deprecation") 71public class LegacyApiSupport { 72 73 private static final String TAG = "ContactsProviderV1"; 74 75 private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 76 77 private static final int PEOPLE = 1; 78 private static final int PEOPLE_ID = 2; 79 private static final int PEOPLE_UPDATE_CONTACT_TIME = 3; 80 private static final int ORGANIZATIONS = 4; 81 private static final int ORGANIZATIONS_ID = 5; 82 private static final int PEOPLE_CONTACTMETHODS = 6; 83 private static final int PEOPLE_CONTACTMETHODS_ID = 7; 84 private static final int CONTACTMETHODS = 8; 85 private static final int CONTACTMETHODS_ID = 9; 86 private static final int PEOPLE_PHONES = 10; 87 private static final int PEOPLE_PHONES_ID = 11; 88 private static final int PHONES = 12; 89 private static final int PHONES_ID = 13; 90 private static final int EXTENSIONS = 14; 91 private static final int EXTENSIONS_ID = 15; 92 private static final int PEOPLE_EXTENSIONS = 16; 93 private static final int PEOPLE_EXTENSIONS_ID = 17; 94 private static final int GROUPS = 18; 95 private static final int GROUPS_ID = 19; 96 private static final int GROUPMEMBERSHIP = 20; 97 private static final int GROUPMEMBERSHIP_ID = 21; 98 private static final int PEOPLE_GROUPMEMBERSHIP = 22; 99 private static final int PEOPLE_GROUPMEMBERSHIP_ID = 23; 100 private static final int PEOPLE_PHOTO = 24; 101 private static final int PHOTOS = 25; 102 private static final int PHOTOS_ID = 26; 103 private static final int PEOPLE_FILTER = 29; 104 private static final int DELETED_PEOPLE = 30; 105 private static final int DELETED_GROUPS = 31; 106 private static final int SEARCH_SUGGESTIONS = 32; 107 private static final int SEARCH_SHORTCUT = 33; 108 private static final int PHONES_FILTER = 34; 109 private static final int LIVE_FOLDERS_PEOPLE = 35; 110 private static final int LIVE_FOLDERS_PEOPLE_GROUP_NAME = 36; 111 private static final int LIVE_FOLDERS_PEOPLE_WITH_PHONES = 37; 112 private static final int LIVE_FOLDERS_PEOPLE_FAVORITES = 38; 113 private static final int CONTACTMETHODS_EMAIL = 39; 114 private static final int GROUP_NAME_MEMBERS = 40; 115 private static final int GROUP_SYSTEM_ID_MEMBERS = 41; 116 private static final int PEOPLE_ORGANIZATIONS = 42; 117 private static final int PEOPLE_ORGANIZATIONS_ID = 43; 118 private static final int SETTINGS = 44; 119 120 private static final String PEOPLE_JOINS = 121 " LEFT OUTER JOIN data name ON (raw_contacts._id = name.raw_contact_id" 122 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = name.mimetype_id)" 123 + "='" + StructuredName.CONTENT_ITEM_TYPE + "')" 124 + " LEFT OUTER JOIN data organization ON (raw_contacts._id = organization.raw_contact_id" 125 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = organization.mimetype_id)" 126 + "='" + Organization.CONTENT_ITEM_TYPE + "' AND organization.is_primary)" 127 + " LEFT OUTER JOIN data email ON (raw_contacts._id = email.raw_contact_id" 128 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = email.mimetype_id)" 129 + "='" + Email.CONTENT_ITEM_TYPE + "' AND email.is_primary)" 130 + " LEFT OUTER JOIN data note ON (raw_contacts._id = note.raw_contact_id" 131 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = note.mimetype_id)" 132 + "='" + Note.CONTENT_ITEM_TYPE + "')" 133 + " LEFT OUTER JOIN data phone ON (raw_contacts._id = phone.raw_contact_id" 134 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = phone.mimetype_id)" 135 + "='" + Phone.CONTENT_ITEM_TYPE + "' AND phone.is_primary)"; 136 137 public static final String DATA_JOINS = 138 " JOIN mimetypes ON (mimetypes._id = data.mimetype_id)" 139 + " JOIN raw_contacts ON (raw_contacts._id = data.raw_contact_id)" 140 + PEOPLE_JOINS; 141 142 public static final String PRESENCE_JOINS = 143 " LEFT OUTER JOIN " + Tables.PRESENCE + 144 " ON (" + Tables.PRESENCE + "." + StatusUpdates.DATA_ID + "=" + 145 "(SELECT MAX(" + StatusUpdates.DATA_ID + ")" + 146 " FROM " + Tables.PRESENCE + 147 " WHERE people._id = " + PresenceColumns.RAW_CONTACT_ID + ")" + 148 " )"; 149 150 private static final String PHONETIC_NAME_SQL = "trim(trim(" 151 + "ifnull(name." + StructuredName.PHONETIC_GIVEN_NAME + ",' ')||' '||" 152 + "ifnull(name." + StructuredName.PHONETIC_MIDDLE_NAME + ",' '))||' '||" 153 + "ifnull(name." + StructuredName.PHONETIC_FAMILY_NAME + ",' ')) "; 154 155 private static final String CONTACT_METHOD_KIND_SQL = 156 "CAST ((CASE WHEN mimetype='" + Email.CONTENT_ITEM_TYPE + "'" 157 + " THEN " + android.provider.Contacts.KIND_EMAIL 158 + " ELSE" 159 + " (CASE WHEN mimetype='" + Im.CONTENT_ITEM_TYPE +"'" 160 + " THEN " + android.provider.Contacts.KIND_IM 161 + " ELSE" 162 + " (CASE WHEN mimetype='" + StructuredPostal.CONTENT_ITEM_TYPE + "'" 163 + " THEN " + android.provider.Contacts.KIND_POSTAL 164 + " ELSE" 165 + " NULL" 166 + " END)" 167 + " END)" 168 + " END) AS INTEGER)"; 169 170 private static final String IM_PROTOCOL_SQL = 171 "(CASE WHEN " + StatusUpdates.PROTOCOL + "=" + Im.PROTOCOL_CUSTOM 172 + " THEN 'custom:'||" + StatusUpdates.CUSTOM_PROTOCOL 173 + " ELSE 'pre:'||" + StatusUpdates.PROTOCOL 174 + " END)"; 175 176 private static String CONTACT_METHOD_DATA_SQL = 177 "(CASE WHEN " + Data.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'" 178 + " THEN (CASE WHEN " + Tables.DATA + "." + Im.PROTOCOL + "=" + Im.PROTOCOL_CUSTOM 179 + " THEN 'custom:'||" + Tables.DATA + "." + Im.CUSTOM_PROTOCOL 180 + " ELSE 'pre:'||" + Tables.DATA + "." + Im.PROTOCOL 181 + " END)" 182 + " ELSE " + Tables.DATA + "." + Email.DATA 183 + " END)"; 184 185 private static final Uri LIVE_FOLDERS_CONTACTS_URI = Uri.withAppendedPath( 186 ContactsContract.AUTHORITY_URI, "live_folders/contacts"); 187 188 private static final Uri LIVE_FOLDERS_CONTACTS_WITH_PHONES_URI = Uri.withAppendedPath( 189 ContactsContract.AUTHORITY_URI, "live_folders/contacts_with_phones"); 190 191 private static final Uri LIVE_FOLDERS_CONTACTS_FAVORITES_URI = Uri.withAppendedPath( 192 ContactsContract.AUTHORITY_URI, "live_folders/favorites"); 193 194 private static final String CONTACTS_UPDATE_LASTTIMECONTACTED = 195 "UPDATE " + Tables.CONTACTS + 196 " SET " + Contacts.LAST_TIME_CONTACTED + "=? " + 197 "WHERE " + Contacts._ID + "=?"; 198 private static final String RAWCONTACTS_UPDATE_LASTTIMECONTACTED = 199 "UPDATE " + Tables.RAW_CONTACTS + " SET " 200 + RawContacts.LAST_TIME_CONTACTED + "=? WHERE " 201 + RawContacts._ID + "=?"; 202 203 private String[] mSelectionArgs1 = new String[1]; 204 private String[] mSelectionArgs2 = new String[2]; 205 206 public interface LegacyTables { 207 public static final String PEOPLE = "view_v1_people"; 208 public static final String PEOPLE_JOIN_PRESENCE = "view_v1_people people " + PRESENCE_JOINS; 209 public static final String GROUPS = "view_v1_groups"; 210 public static final String ORGANIZATIONS = "view_v1_organizations"; 211 public static final String CONTACT_METHODS = "view_v1_contact_methods"; 212 public static final String PHONES = "view_v1_phones"; 213 public static final String EXTENSIONS = "view_v1_extensions"; 214 public static final String GROUP_MEMBERSHIP = "view_v1_group_membership"; 215 public static final String PHOTOS = "view_v1_photos"; 216 public static final String SETTINGS = "v1_settings"; 217 } 218 219 private static final String[] ORGANIZATION_MIME_TYPES = new String[] { 220 Organization.CONTENT_ITEM_TYPE 221 }; 222 223 private static final String[] CONTACT_METHOD_MIME_TYPES = new String[] { 224 Email.CONTENT_ITEM_TYPE, 225 Im.CONTENT_ITEM_TYPE, 226 StructuredPostal.CONTENT_ITEM_TYPE, 227 }; 228 229 private static final String[] PHONE_MIME_TYPES = new String[] { 230 Phone.CONTENT_ITEM_TYPE 231 }; 232 233 private static final String[] PHOTO_MIME_TYPES = new String[] { 234 Photo.CONTENT_ITEM_TYPE 235 }; 236 237 private static final String[] GROUP_MEMBERSHIP_MIME_TYPES = new String[] { 238 GroupMembership.CONTENT_ITEM_TYPE 239 }; 240 241 private static final String[] EXTENSION_MIME_TYPES = new String[] { 242 android.provider.Contacts.Extensions.CONTENT_ITEM_TYPE 243 }; 244 245 private interface IdQuery { 246 String[] COLUMNS = { BaseColumns._ID }; 247 248 int _ID = 0; 249 } 250 251 /** 252 * A custom data row that is used to store legacy photo data fields no 253 * longer directly supported by the API. 254 */ 255 private interface LegacyPhotoData { 256 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo_v1_extras"; 257 258 public static final String PHOTO_DATA_ID = Data.DATA1; 259 public static final String LOCAL_VERSION = Data.DATA2; 260 public static final String DOWNLOAD_REQUIRED = Data.DATA3; 261 public static final String EXISTS_ON_SERVER = Data.DATA4; 262 public static final String SYNC_ERROR = Data.DATA5; 263 } 264 265 public static final String LEGACY_PHOTO_JOIN = 266 " LEFT OUTER JOIN data legacy_photo ON (raw_contacts._id = legacy_photo.raw_contact_id" 267 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = legacy_photo.mimetype_id)" 268 + "='" + LegacyPhotoData.CONTENT_ITEM_TYPE + "'" 269 + " AND " + DataColumns.CONCRETE_ID + " = legacy_photo." + LegacyPhotoData.PHOTO_DATA_ID 270 + ")"; 271 272 private static final HashMap<String, String> sPeopleProjectionMap; 273 private static final HashMap<String, String> sOrganizationProjectionMap; 274 private static final HashMap<String, String> sContactMethodProjectionMap; 275 private static final HashMap<String, String> sPhoneProjectionMap; 276 private static final HashMap<String, String> sExtensionProjectionMap; 277 private static final HashMap<String, String> sGroupProjectionMap; 278 private static final HashMap<String, String> sGroupMembershipProjectionMap; 279 private static final HashMap<String, String> sPhotoProjectionMap; 280 281 static { 282 283 // Contacts URI matching table 284 UriMatcher matcher = sUriMatcher; 285 286 String authority = android.provider.Contacts.AUTHORITY; 287 matcher.addURI(authority, "extensions", EXTENSIONS); 288 matcher.addURI(authority, "extensions/#", EXTENSIONS_ID); 289 matcher.addURI(authority, "groups", GROUPS); 290 matcher.addURI(authority, "groups/#", GROUPS_ID); 291 matcher.addURI(authority, "groups/name/*/members", GROUP_NAME_MEMBERS); 292// matcher.addURI(authority, "groups/name/*/members/filter/*", 293// GROUP_NAME_MEMBERS_FILTER); 294 matcher.addURI(authority, "groups/system_id/*/members", GROUP_SYSTEM_ID_MEMBERS); 295// matcher.addURI(authority, "groups/system_id/*/members/filter/*", 296// GROUP_SYSTEM_ID_MEMBERS_FILTER); 297 matcher.addURI(authority, "groupmembership", GROUPMEMBERSHIP); 298 matcher.addURI(authority, "groupmembership/#", GROUPMEMBERSHIP_ID); 299// matcher.addURI(authority, "groupmembershipraw", GROUPMEMBERSHIP_RAW); 300 matcher.addURI(authority, "people", PEOPLE); 301// matcher.addURI(authority, "people/strequent", PEOPLE_STREQUENT); 302// matcher.addURI(authority, "people/strequent/filter/*", PEOPLE_STREQUENT_FILTER); 303 matcher.addURI(authority, "people/filter/*", PEOPLE_FILTER); 304// matcher.addURI(authority, "people/with_phones_filter/*", 305// PEOPLE_WITH_PHONES_FILTER); 306// matcher.addURI(authority, "people/with_email_or_im_filter/*", 307// PEOPLE_WITH_EMAIL_OR_IM_FILTER); 308 matcher.addURI(authority, "people/#", PEOPLE_ID); 309 matcher.addURI(authority, "people/#/extensions", PEOPLE_EXTENSIONS); 310 matcher.addURI(authority, "people/#/extensions/#", PEOPLE_EXTENSIONS_ID); 311 matcher.addURI(authority, "people/#/phones", PEOPLE_PHONES); 312 matcher.addURI(authority, "people/#/phones/#", PEOPLE_PHONES_ID); 313// matcher.addURI(authority, "people/#/phones_with_presence", 314// PEOPLE_PHONES_WITH_PRESENCE); 315 matcher.addURI(authority, "people/#/photo", PEOPLE_PHOTO); 316// matcher.addURI(authority, "people/#/photo/data", PEOPLE_PHOTO_DATA); 317 matcher.addURI(authority, "people/#/contact_methods", PEOPLE_CONTACTMETHODS); 318// matcher.addURI(authority, "people/#/contact_methods_with_presence", 319// PEOPLE_CONTACTMETHODS_WITH_PRESENCE); 320 matcher.addURI(authority, "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID); 321 matcher.addURI(authority, "people/#/organizations", PEOPLE_ORGANIZATIONS); 322 matcher.addURI(authority, "people/#/organizations/#", PEOPLE_ORGANIZATIONS_ID); 323 matcher.addURI(authority, "people/#/groupmembership", PEOPLE_GROUPMEMBERSHIP); 324 matcher.addURI(authority, "people/#/groupmembership/#", PEOPLE_GROUPMEMBERSHIP_ID); 325// matcher.addURI(authority, "people/raw", PEOPLE_RAW); 326// matcher.addURI(authority, "people/owner", PEOPLE_OWNER); 327 matcher.addURI(authority, "people/#/update_contact_time", 328 PEOPLE_UPDATE_CONTACT_TIME); 329 matcher.addURI(authority, "deleted_people", DELETED_PEOPLE); 330 matcher.addURI(authority, "deleted_groups", DELETED_GROUPS); 331 matcher.addURI(authority, "phones", PHONES); 332// matcher.addURI(authority, "phones_with_presence", PHONES_WITH_PRESENCE); 333 matcher.addURI(authority, "phones/filter/*", PHONES_FILTER); 334// matcher.addURI(authority, "phones/filter_name/*", PHONES_FILTER_NAME); 335// matcher.addURI(authority, "phones/mobile_filter_name/*", 336// PHONES_MOBILE_FILTER_NAME); 337 matcher.addURI(authority, "phones/#", PHONES_ID); 338 matcher.addURI(authority, "photos", PHOTOS); 339 matcher.addURI(authority, "photos/#", PHOTOS_ID); 340 matcher.addURI(authority, "contact_methods", CONTACTMETHODS); 341 matcher.addURI(authority, "contact_methods/email", CONTACTMETHODS_EMAIL); 342// matcher.addURI(authority, "contact_methods/email/*", CONTACTMETHODS_EMAIL_FILTER); 343 matcher.addURI(authority, "contact_methods/#", CONTACTMETHODS_ID); 344// matcher.addURI(authority, "contact_methods/with_presence", 345// CONTACTMETHODS_WITH_PRESENCE); 346 matcher.addURI(authority, "organizations", ORGANIZATIONS); 347 matcher.addURI(authority, "organizations/#", ORGANIZATIONS_ID); 348// matcher.addURI(authority, "voice_dialer_timestamp", VOICE_DIALER_TIMESTAMP); 349 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_QUERY, 350 SEARCH_SUGGESTIONS); 351 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 352 SEARCH_SUGGESTIONS); 353 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 354 SEARCH_SHORTCUT); 355 matcher.addURI(authority, "settings", SETTINGS); 356 357 matcher.addURI(authority, "live_folders/people", LIVE_FOLDERS_PEOPLE); 358 matcher.addURI(authority, "live_folders/people/*", 359 LIVE_FOLDERS_PEOPLE_GROUP_NAME); 360 matcher.addURI(authority, "live_folders/people_with_phones", 361 LIVE_FOLDERS_PEOPLE_WITH_PHONES); 362 matcher.addURI(authority, "live_folders/favorites", 363 LIVE_FOLDERS_PEOPLE_FAVORITES); 364 365 366 HashMap<String, String> peopleProjectionMap = new HashMap<String, String>(); 367 peopleProjectionMap.put(People.NAME, People.NAME); 368 peopleProjectionMap.put(People.DISPLAY_NAME, People.DISPLAY_NAME); 369 peopleProjectionMap.put(People.PHONETIC_NAME, People.PHONETIC_NAME); 370 peopleProjectionMap.put(People.NOTES, People.NOTES); 371 peopleProjectionMap.put(People.TIMES_CONTACTED, People.TIMES_CONTACTED); 372 peopleProjectionMap.put(People.LAST_TIME_CONTACTED, People.LAST_TIME_CONTACTED); 373 peopleProjectionMap.put(People.CUSTOM_RINGTONE, People.CUSTOM_RINGTONE); 374 peopleProjectionMap.put(People.SEND_TO_VOICEMAIL, People.SEND_TO_VOICEMAIL); 375 peopleProjectionMap.put(People.STARRED, People.STARRED); 376 peopleProjectionMap.put(People.PRIMARY_ORGANIZATION_ID, People.PRIMARY_ORGANIZATION_ID); 377 peopleProjectionMap.put(People.PRIMARY_EMAIL_ID, People.PRIMARY_EMAIL_ID); 378 peopleProjectionMap.put(People.PRIMARY_PHONE_ID, People.PRIMARY_PHONE_ID); 379 380 sPeopleProjectionMap = new HashMap<String, String>(peopleProjectionMap); 381 sPeopleProjectionMap.put(People._ID, People._ID); 382 sPeopleProjectionMap.put(People.NUMBER, People.NUMBER); 383 sPeopleProjectionMap.put(People.TYPE, People.TYPE); 384 sPeopleProjectionMap.put(People.LABEL, People.LABEL); 385 sPeopleProjectionMap.put(People.NUMBER_KEY, People.NUMBER_KEY); 386 sPeopleProjectionMap.put(People.IM_PROTOCOL, IM_PROTOCOL_SQL + " AS " + People.IM_PROTOCOL); 387 sPeopleProjectionMap.put(People.IM_HANDLE, People.IM_HANDLE); 388 sPeopleProjectionMap.put(People.IM_ACCOUNT, People.IM_ACCOUNT); 389 sPeopleProjectionMap.put(People.PRESENCE_STATUS, People.PRESENCE_STATUS); 390 sPeopleProjectionMap.put(People.PRESENCE_CUSTOM_STATUS, 391 "(SELECT " + StatusUpdates.STATUS + 392 " FROM " + Tables.STATUS_UPDATES + 393 " JOIN " + Tables.DATA + 394 " ON(" + StatusUpdatesColumns.DATA_ID + "=" + DataColumns.CONCRETE_ID + ")" + 395 " WHERE " + DataColumns.CONCRETE_RAW_CONTACT_ID + "=people." + People._ID + 396 " ORDER BY " + StatusUpdates.STATUS_TIMESTAMP + " DESC " + 397 " LIMIT 1" + 398 ") AS " + People.PRESENCE_CUSTOM_STATUS); 399 400 sOrganizationProjectionMap = new HashMap<String, String>(); 401 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations._ID, 402 android.provider.Contacts.Organizations._ID); 403 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.PERSON_ID, 404 android.provider.Contacts.Organizations.PERSON_ID); 405 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.ISPRIMARY, 406 android.provider.Contacts.Organizations.ISPRIMARY); 407 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.COMPANY, 408 android.provider.Contacts.Organizations.COMPANY); 409 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.TYPE, 410 android.provider.Contacts.Organizations.TYPE); 411 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.LABEL, 412 android.provider.Contacts.Organizations.LABEL); 413 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.TITLE, 414 android.provider.Contacts.Organizations.TITLE); 415 416 sContactMethodProjectionMap = new HashMap<String, String>(peopleProjectionMap); 417 sContactMethodProjectionMap.put(ContactMethods._ID, ContactMethods._ID); 418 sContactMethodProjectionMap.put(ContactMethods.PERSON_ID, ContactMethods.PERSON_ID); 419 sContactMethodProjectionMap.put(ContactMethods.KIND, ContactMethods.KIND); 420 sContactMethodProjectionMap.put(ContactMethods.ISPRIMARY, ContactMethods.ISPRIMARY); 421 sContactMethodProjectionMap.put(ContactMethods.TYPE, ContactMethods.TYPE); 422 sContactMethodProjectionMap.put(ContactMethods.DATA, ContactMethods.DATA); 423 sContactMethodProjectionMap.put(ContactMethods.LABEL, ContactMethods.LABEL); 424 sContactMethodProjectionMap.put(ContactMethods.AUX_DATA, ContactMethods.AUX_DATA); 425 426 sPhoneProjectionMap = new HashMap<String, String>(peopleProjectionMap); 427 sPhoneProjectionMap.put(android.provider.Contacts.Phones._ID, 428 android.provider.Contacts.Phones._ID); 429 sPhoneProjectionMap.put(android.provider.Contacts.Phones.PERSON_ID, 430 android.provider.Contacts.Phones.PERSON_ID); 431 sPhoneProjectionMap.put(android.provider.Contacts.Phones.ISPRIMARY, 432 android.provider.Contacts.Phones.ISPRIMARY); 433 sPhoneProjectionMap.put(android.provider.Contacts.Phones.NUMBER, 434 android.provider.Contacts.Phones.NUMBER); 435 sPhoneProjectionMap.put(android.provider.Contacts.Phones.TYPE, 436 android.provider.Contacts.Phones.TYPE); 437 sPhoneProjectionMap.put(android.provider.Contacts.Phones.LABEL, 438 android.provider.Contacts.Phones.LABEL); 439 sPhoneProjectionMap.put(android.provider.Contacts.Phones.NUMBER_KEY, 440 android.provider.Contacts.Phones.NUMBER_KEY); 441 442 sExtensionProjectionMap = new HashMap<String, String>(); 443 sExtensionProjectionMap.put(android.provider.Contacts.Extensions._ID, 444 android.provider.Contacts.Extensions._ID); 445 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.PERSON_ID, 446 android.provider.Contacts.Extensions.PERSON_ID); 447 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.NAME, 448 android.provider.Contacts.Extensions.NAME); 449 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.VALUE, 450 android.provider.Contacts.Extensions.VALUE); 451 452 sGroupProjectionMap = new HashMap<String, String>(); 453 sGroupProjectionMap.put(android.provider.Contacts.Groups._ID, 454 android.provider.Contacts.Groups._ID); 455 sGroupProjectionMap.put(android.provider.Contacts.Groups.NAME, 456 android.provider.Contacts.Groups.NAME); 457 sGroupProjectionMap.put(android.provider.Contacts.Groups.NOTES, 458 android.provider.Contacts.Groups.NOTES); 459 sGroupProjectionMap.put(android.provider.Contacts.Groups.SYSTEM_ID, 460 android.provider.Contacts.Groups.SYSTEM_ID); 461 462 sGroupMembershipProjectionMap = new HashMap<String, String>(sGroupProjectionMap); 463 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership._ID, 464 android.provider.Contacts.GroupMembership._ID); 465 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership.PERSON_ID, 466 android.provider.Contacts.GroupMembership.PERSON_ID); 467 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership.GROUP_ID, 468 android.provider.Contacts.GroupMembership.GROUP_ID); 469 sGroupMembershipProjectionMap.put( 470 android.provider.Contacts.GroupMembership.GROUP_SYNC_ID, 471 android.provider.Contacts.GroupMembership.GROUP_SYNC_ID); 472 sGroupMembershipProjectionMap.put( 473 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT, 474 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT); 475 sGroupMembershipProjectionMap.put( 476 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT_TYPE, 477 android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT_TYPE); 478 479 sPhotoProjectionMap = new HashMap<String, String>(); 480 sPhotoProjectionMap.put(android.provider.Contacts.Photos._ID, 481 android.provider.Contacts.Photos._ID); 482 sPhotoProjectionMap.put(android.provider.Contacts.Photos.PERSON_ID, 483 android.provider.Contacts.Photos.PERSON_ID); 484 sPhotoProjectionMap.put(android.provider.Contacts.Photos.DATA, 485 android.provider.Contacts.Photos.DATA); 486 sPhotoProjectionMap.put(android.provider.Contacts.Photos.LOCAL_VERSION, 487 android.provider.Contacts.Photos.LOCAL_VERSION); 488 sPhotoProjectionMap.put(android.provider.Contacts.Photos.DOWNLOAD_REQUIRED, 489 android.provider.Contacts.Photos.DOWNLOAD_REQUIRED); 490 sPhotoProjectionMap.put(android.provider.Contacts.Photos.EXISTS_ON_SERVER, 491 android.provider.Contacts.Photos.EXISTS_ON_SERVER); 492 sPhotoProjectionMap.put(android.provider.Contacts.Photos.SYNC_ERROR, 493 android.provider.Contacts.Photos.SYNC_ERROR); 494 } 495 496 private final Context mContext; 497 private final ContactsDatabaseHelper mDbHelper; 498 private final ContactsProvider2 mContactsProvider; 499 private final NameSplitter mPhoneticNameSplitter; 500 private final GlobalSearchSupport mGlobalSearchSupport; 501 502 private final SQLiteStatement mDataMimetypeQuery; 503 private final SQLiteStatement mDataRawContactIdQuery; 504 505 private final ContentValues mValues = new ContentValues(); 506 private final ContentValues mValues2 = new ContentValues(); 507 private final ContentValues mValues3 = new ContentValues(); 508 private boolean mDefaultAccountKnown; 509 private Account mAccount; 510 511 private long mMimetypeEmail; 512 private long mMimetypeIm; 513 private long mMimetypePostal; 514 515 516 public LegacyApiSupport(Context context, ContactsDatabaseHelper contactsDatabaseHelper, 517 ContactsProvider2 contactsProvider, GlobalSearchSupport globalSearchSupport) { 518 mContext = context; 519 mContactsProvider = contactsProvider; 520 mDbHelper = contactsDatabaseHelper; 521 mGlobalSearchSupport = globalSearchSupport; 522 523 mPhoneticNameSplitter = new NameSplitter("", "", "", context 524 .getString(com.android.internal.R.string.common_name_conjunctions), Locale 525 .getDefault()); 526 527 SQLiteDatabase db = mDbHelper.getReadableDatabase(); 528 mDataMimetypeQuery = db.compileStatement( 529 "SELECT " + DataColumns.MIMETYPE_ID + 530 " FROM " + Tables.DATA + 531 " WHERE " + Data._ID + "=?"); 532 533 mDataRawContactIdQuery = db.compileStatement( 534 "SELECT " + Data.RAW_CONTACT_ID + 535 " FROM " + Tables.DATA + 536 " WHERE " + Data._ID + "=?"); 537 538 mMimetypeEmail = mDbHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE); 539 mMimetypeIm = mDbHelper.getMimeTypeId(Im.CONTENT_ITEM_TYPE); 540 mMimetypePostal = mDbHelper.getMimeTypeId(StructuredPostal.CONTENT_ITEM_TYPE); 541 } 542 543 private void ensureDefaultAccount() { 544 if (!mDefaultAccountKnown) { 545 mAccount = mContactsProvider.getDefaultAccount(); 546 mDefaultAccountKnown = true; 547 } 548 } 549 550 public static void createDatabase(SQLiteDatabase db) { 551 Log.i(TAG, "Bootstrapping database legacy support"); 552 createViews(db); 553 createSettingsTable(db); 554 } 555 556 public static void createViews(SQLiteDatabase db) { 557 558 String peopleColumns = "name." + StructuredName.DISPLAY_NAME 559 + " AS " + People.NAME + ", " + 560 Tables.RAW_CONTACTS + "." + RawContactsColumns.DISPLAY_NAME 561 + " AS " + People.DISPLAY_NAME + ", " + 562 PHONETIC_NAME_SQL 563 + " AS " + People.PHONETIC_NAME + " , " + 564 "note." + Note.NOTE 565 + " AS " + People.NOTES + ", " + 566 RawContacts.ACCOUNT_NAME + ", " + 567 RawContacts.ACCOUNT_TYPE + ", " + 568 Tables.RAW_CONTACTS + "." + RawContacts.TIMES_CONTACTED 569 + " AS " + People.TIMES_CONTACTED + ", " + 570 Tables.RAW_CONTACTS + "." + RawContacts.LAST_TIME_CONTACTED 571 + " AS " + People.LAST_TIME_CONTACTED + ", " + 572 Tables.RAW_CONTACTS + "." + RawContacts.CUSTOM_RINGTONE 573 + " AS " + People.CUSTOM_RINGTONE + ", " + 574 Tables.RAW_CONTACTS + "." + RawContacts.SEND_TO_VOICEMAIL 575 + " AS " + People.SEND_TO_VOICEMAIL + ", " + 576 Tables.RAW_CONTACTS + "." + RawContacts.STARRED 577 + " AS " + People.STARRED + ", " + 578 "organization." + Data._ID 579 + " AS " + People.PRIMARY_ORGANIZATION_ID + ", " + 580 "email." + Data._ID 581 + " AS " + People.PRIMARY_EMAIL_ID + ", " + 582 "phone." + Data._ID 583 + " AS " + People.PRIMARY_PHONE_ID + ", " + 584 "phone." + Phone.NUMBER 585 + " AS " + People.NUMBER + ", " + 586 "phone." + Phone.TYPE 587 + " AS " + People.TYPE + ", " + 588 "phone." + Phone.LABEL 589 + " AS " + People.LABEL + ", " + 590 "_PHONE_NUMBER_STRIPPED_REVERSED(phone." + Phone.NUMBER + ")" 591 + " AS " + People.NUMBER_KEY; 592 593 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.PEOPLE + ";"); 594 db.execSQL("CREATE VIEW " + LegacyTables.PEOPLE + " AS SELECT " + 595 RawContactsColumns.CONCRETE_ID 596 + " AS " + android.provider.Contacts.People._ID + ", " + 597 peopleColumns + 598 " FROM " + Tables.RAW_CONTACTS + PEOPLE_JOINS + 599 " WHERE " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0;"); 600 601 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.ORGANIZATIONS + ";"); 602 db.execSQL("CREATE VIEW " + LegacyTables.ORGANIZATIONS + " AS SELECT " + 603 DataColumns.CONCRETE_ID 604 + " AS " + android.provider.Contacts.Organizations._ID + ", " + 605 Data.RAW_CONTACT_ID 606 + " AS " + android.provider.Contacts.Organizations.PERSON_ID + ", " + 607 Data.IS_PRIMARY 608 + " AS " + android.provider.Contacts.Organizations.ISPRIMARY + ", " + 609 RawContacts.ACCOUNT_NAME + ", " + 610 RawContacts.ACCOUNT_TYPE + ", " + 611 Organization.COMPANY 612 + " AS " + android.provider.Contacts.Organizations.COMPANY + ", " + 613 Organization.TYPE 614 + " AS " + android.provider.Contacts.Organizations.TYPE + ", " + 615 Organization.LABEL 616 + " AS " + android.provider.Contacts.Organizations.LABEL + ", " + 617 Organization.TITLE 618 + " AS " + android.provider.Contacts.Organizations.TITLE + 619 " FROM " + Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS + 620 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 621 + Organization.CONTENT_ITEM_TYPE + "'" 622 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=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 ";"); 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 ";"); 676 677 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.EXTENSIONS + ";"); 678 db.execSQL("CREATE VIEW " + LegacyTables.EXTENSIONS + " AS SELECT " + 679 DataColumns.CONCRETE_ID 680 + " AS " + android.provider.Contacts.Extensions._ID + ", " + 681 DataColumns.CONCRETE_RAW_CONTACT_ID 682 + " AS " + android.provider.Contacts.Extensions.PERSON_ID + ", " + 683 RawContacts.ACCOUNT_NAME + ", " + 684 RawContacts.ACCOUNT_TYPE + ", " + 685 ExtensionsColumns.NAME 686 + " AS " + android.provider.Contacts.Extensions.NAME + ", " + 687 ExtensionsColumns.VALUE 688 + " AS " + android.provider.Contacts.Extensions.VALUE + 689 " FROM " + Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS + 690 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 691 + android.provider.Contacts.Extensions.CONTENT_ITEM_TYPE + "'" 692 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" + 693 ";"); 694 695 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.GROUPS + ";"); 696 db.execSQL("CREATE VIEW " + LegacyTables.GROUPS + " AS SELECT " + 697 GroupsColumns.CONCRETE_ID + " AS " + android.provider.Contacts.Groups._ID + ", " + 698 Groups.ACCOUNT_NAME + ", " + 699 Groups.ACCOUNT_TYPE + ", " + 700 Groups.TITLE + " AS " + android.provider.Contacts.Groups.NAME + ", " + 701 Groups.NOTES + " AS " + android.provider.Contacts.Groups.NOTES + " , " + 702 Groups.SYSTEM_ID + " AS " + android.provider.Contacts.Groups.SYSTEM_ID + 703 " FROM " + Tables.GROUPS + 704 ";"); 705 706 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.GROUP_MEMBERSHIP + ";"); 707 db.execSQL("CREATE VIEW " + LegacyTables.GROUP_MEMBERSHIP + " AS SELECT " + 708 DataColumns.CONCRETE_ID 709 + " AS " + android.provider.Contacts.GroupMembership._ID + ", " + 710 DataColumns.CONCRETE_RAW_CONTACT_ID 711 + " AS " + android.provider.Contacts.GroupMembership.PERSON_ID + ", " + 712 Tables.RAW_CONTACTS + "." + RawContacts.ACCOUNT_NAME 713 + " AS " + RawContacts.ACCOUNT_NAME + ", " + 714 Tables.RAW_CONTACTS + "." + RawContacts.ACCOUNT_TYPE 715 + " AS " + RawContacts.ACCOUNT_TYPE + ", " + 716 GroupMembership.GROUP_ROW_ID 717 + " AS " + android.provider.Contacts.GroupMembership.GROUP_ID + ", " + 718 Groups.TITLE 719 + " AS " + android.provider.Contacts.GroupMembership.NAME + ", " + 720 Groups.NOTES 721 + " AS " + android.provider.Contacts.GroupMembership.NOTES + ", " + 722 Groups.SYSTEM_ID 723 + " AS " + android.provider.Contacts.GroupMembership.SYSTEM_ID + ", " + 724 GroupsColumns.CONCRETE_SOURCE_ID 725 + " AS " 726 + android.provider.Contacts.GroupMembership.GROUP_SYNC_ID + ", " + 727 GroupsColumns.CONCRETE_ACCOUNT_NAME 728 + " AS " 729 + android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT + ", " + 730 GroupsColumns.CONCRETE_ACCOUNT_TYPE 731 + " AS " 732 + android.provider.Contacts.GroupMembership.GROUP_SYNC_ACCOUNT_TYPE + 733 " FROM " + Tables.DATA_JOIN_PACKAGES_MIMETYPES_RAW_CONTACTS_GROUPS + 734 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 735 + GroupMembership.CONTENT_ITEM_TYPE + "'" 736 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" + 737 ";"); 738 739 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.PHOTOS + ";"); 740 db.execSQL("CREATE VIEW " + LegacyTables.PHOTOS + " AS SELECT " + 741 DataColumns.CONCRETE_ID 742 + " AS " + android.provider.Contacts.Photos._ID + ", " + 743 DataColumns.CONCRETE_RAW_CONTACT_ID 744 + " AS " + android.provider.Contacts.Photos.PERSON_ID + ", " + 745 RawContacts.ACCOUNT_NAME + ", " + 746 RawContacts.ACCOUNT_TYPE + ", " + 747 Tables.DATA + "." + Photo.PHOTO 748 + " AS " + android.provider.Contacts.Photos.DATA + ", " + 749 "legacy_photo." + LegacyPhotoData.EXISTS_ON_SERVER 750 + " AS " + android.provider.Contacts.Photos.EXISTS_ON_SERVER + ", " + 751 "legacy_photo." + LegacyPhotoData.DOWNLOAD_REQUIRED 752 + " AS " + android.provider.Contacts.Photos.DOWNLOAD_REQUIRED + ", " + 753 "legacy_photo." + LegacyPhotoData.LOCAL_VERSION 754 + " AS " + android.provider.Contacts.Photos.LOCAL_VERSION + ", " + 755 "legacy_photo." + LegacyPhotoData.SYNC_ERROR 756 + " AS " + android.provider.Contacts.Photos.SYNC_ERROR + 757 " FROM " + Tables.DATA + DATA_JOINS + LEGACY_PHOTO_JOIN + 758 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 759 + Photo.CONTENT_ITEM_TYPE + "'" 760 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" + 761 ";"); 762 763 } 764 765 public static void createSettingsTable(SQLiteDatabase db) { 766 db.execSQL("DROP TABLE IF EXISTS " + LegacyTables.SETTINGS + ";"); 767 db.execSQL("CREATE TABLE " + LegacyTables.SETTINGS + " (" + 768 android.provider.Contacts.Settings._ID + " INTEGER PRIMARY KEY," + 769 android.provider.Contacts.Settings._SYNC_ACCOUNT + " TEXT," + 770 android.provider.Contacts.Settings._SYNC_ACCOUNT_TYPE + " TEXT," + 771 android.provider.Contacts.Settings.KEY + " STRING NOT NULL," + 772 android.provider.Contacts.Settings.VALUE + " STRING " + 773 ");"); 774 } 775 776 public Uri insert(Uri uri, ContentValues values) { 777 ensureDefaultAccount(); 778 final int match = sUriMatcher.match(uri); 779 long id = 0; 780 switch (match) { 781 case PEOPLE: 782 id = insertPeople(values); 783 break; 784 785 case ORGANIZATIONS: 786 id = insertOrganization(values); 787 break; 788 789 case PEOPLE_CONTACTMETHODS: { 790 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 791 id = insertContactMethod(rawContactId, values); 792 break; 793 } 794 795 case CONTACTMETHODS: { 796 long rawContactId = getRequiredValue(values, ContactMethods.PERSON_ID); 797 id = insertContactMethod(rawContactId, values); 798 break; 799 } 800 801 case PHONES: { 802 long rawContactId = getRequiredValue(values, 803 android.provider.Contacts.Phones.PERSON_ID); 804 id = insertPhone(rawContactId, values); 805 break; 806 } 807 808 case PEOPLE_PHONES: { 809 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 810 id = insertPhone(rawContactId, values); 811 break; 812 } 813 814 case EXTENSIONS: { 815 long rawContactId = getRequiredValue(values, 816 android.provider.Contacts.Extensions.PERSON_ID); 817 id = insertExtension(rawContactId, values); 818 break; 819 } 820 821 case GROUPS: 822 id = insertGroup(values); 823 break; 824 825 case GROUPMEMBERSHIP: { 826 long rawContactId = getRequiredValue(values, 827 android.provider.Contacts.GroupMembership.PERSON_ID); 828 long groupId = getRequiredValue(values, 829 android.provider.Contacts.GroupMembership.GROUP_ID); 830 id = insertGroupMembership(rawContactId, groupId); 831 break; 832 } 833 834 default: 835 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 836 } 837 838 if (id < 0) { 839 return null; 840 } 841 842 final Uri result = ContentUris.withAppendedId(uri, id); 843 onChange(result); 844 return result; 845 } 846 847 private long getRequiredValue(ContentValues values, String column) { 848 if (!values.containsKey(column)) { 849 throw new RuntimeException("Required value: " + column); 850 } 851 852 return values.getAsLong(column); 853 } 854 855 private long insertPeople(ContentValues values) { 856 parsePeopleValues(values); 857 858 Uri contactUri = mContactsProvider.insertInTransaction(RawContacts.CONTENT_URI, mValues); 859 long rawContactId = ContentUris.parseId(contactUri); 860 861 if (mValues2.size() != 0) { 862 mValues2.put(Data.RAW_CONTACT_ID, rawContactId); 863 mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues2); 864 } 865 if (mValues3.size() != 0) { 866 mValues3.put(Data.RAW_CONTACT_ID, rawContactId); 867 mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues3); 868 } 869 870 return rawContactId; 871 } 872 873 private long insertOrganization(ContentValues values) { 874 parseOrganizationValues(values); 875 ContactsDatabaseHelper.copyLongValue(mValues, Data.RAW_CONTACT_ID, 876 values, android.provider.Contacts.Organizations.PERSON_ID); 877 878 Uri uri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 879 880 return ContentUris.parseId(uri); 881 } 882 883 private long insertPhone(long rawContactId, ContentValues values) { 884 parsePhoneValues(values); 885 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 886 887 Uri uri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 888 889 return ContentUris.parseId(uri); 890 } 891 892 private long insertContactMethod(long rawContactId, ContentValues values) { 893 Integer kind = values.getAsInteger(ContactMethods.KIND); 894 if (kind == null) { 895 throw new RuntimeException("Required value: " + ContactMethods.KIND); 896 } 897 898 parseContactMethodValues(kind, values); 899 900 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 901 Uri uri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 902 return ContentUris.parseId(uri); 903 } 904 905 private long insertExtension(long rawContactId, ContentValues values) { 906 mValues.clear(); 907 908 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 909 mValues.put(Data.MIMETYPE, android.provider.Contacts.Extensions.CONTENT_ITEM_TYPE); 910 911 parseExtensionValues(values); 912 913 Uri uri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 914 return ContentUris.parseId(uri); 915 } 916 917 private long insertGroup(ContentValues values) { 918 parseGroupValues(values); 919 920 if (mAccount != null) { 921 mValues.put(Groups.ACCOUNT_NAME, mAccount.name); 922 mValues.put(Groups.ACCOUNT_TYPE, mAccount.type); 923 } 924 925 Uri uri = mContactsProvider.insertInTransaction(Groups.CONTENT_URI, mValues); 926 return ContentUris.parseId(uri); 927 } 928 929 private long insertGroupMembership(long rawContactId, long groupId) { 930 mValues.clear(); 931 932 mValues.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE); 933 mValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 934 mValues.put(GroupMembership.GROUP_ROW_ID, groupId); 935 936 Uri uri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 937 return ContentUris.parseId(uri); 938 } 939 940 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 941 ensureDefaultAccount(); 942 943 int match = sUriMatcher.match(uri); 944 int count = 0; 945 switch(match) { 946 case PEOPLE_UPDATE_CONTACT_TIME: { 947 count = updateContactTime(uri, values); 948 break; 949 } 950 951 case PEOPLE_PHOTO: { 952 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 953 return updatePhoto(rawContactId, values); 954 } 955 956 case SETTINGS: { 957 return updateSettings(values); 958 } 959 960 case GROUPMEMBERSHIP: 961 case GROUPMEMBERSHIP_ID: 962 case -1: { 963 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 964 } 965 966 default: { 967 count = updateAll(uri, match, values, selection, selectionArgs); 968 } 969 } 970 971 if (count > 0) { 972 mContext.getContentResolver().notifyChange(uri, null); 973 } 974 975 return count; 976 } 977 978 private int updateAll(Uri uri, final int match, ContentValues values, String selection, 979 String[] selectionArgs) { 980 Cursor c = query(uri, IdQuery.COLUMNS, selection, selectionArgs, null, null); 981 if (c == null) { 982 return 0; 983 } 984 985 int count = 0; 986 try { 987 while (c.moveToNext()) { 988 long id = c.getLong(IdQuery._ID); 989 count += update(match, id, values); 990 } 991 } finally { 992 c.close(); 993 } 994 995 return count; 996 } 997 998 public int update(int match, long id, ContentValues values) { 999 int count = 0; 1000 switch(match) { 1001 case PEOPLE: 1002 case PEOPLE_ID: { 1003 count = updatePeople(id, values); 1004 break; 1005 } 1006 1007 case ORGANIZATIONS: 1008 case ORGANIZATIONS_ID: { 1009 count = updateOrganizations(id, values); 1010 break; 1011 } 1012 1013 case PHONES: 1014 case PHONES_ID: { 1015 count = updatePhones(id, values); 1016 break; 1017 } 1018 1019 case CONTACTMETHODS: 1020 case CONTACTMETHODS_ID: { 1021 count = updateContactMethods(id, values); 1022 break; 1023 } 1024 1025 case EXTENSIONS: 1026 case EXTENSIONS_ID: { 1027 count = updateExtensions(id, values); 1028 break; 1029 } 1030 1031 case GROUPS: 1032 case GROUPS_ID: { 1033 count = updateGroups(id, values); 1034 break; 1035 } 1036 1037 case PHOTOS: 1038 case PHOTOS_ID: 1039 count = updatePhotoByDataId(id, values); 1040 break; 1041 } 1042 1043 return count; 1044 } 1045 1046 private int updatePeople(long rawContactId, ContentValues values) { 1047 parsePeopleValues(values); 1048 1049 int count = mContactsProvider.updateInTransaction(RawContacts.CONTENT_URI, 1050 mValues, RawContacts._ID + "=" + rawContactId, null); 1051 1052 if (count == 0) { 1053 return 0; 1054 } 1055 1056 if (mValues2.size() != 0) { 1057 Uri dataUri = findFirstDataRow(rawContactId, StructuredName.CONTENT_ITEM_TYPE); 1058 if (dataUri != null) { 1059 mContactsProvider.updateInTransaction(dataUri, mValues2, null, null); 1060 } else { 1061 mValues2.put(Data.RAW_CONTACT_ID, rawContactId); 1062 mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues2); 1063 } 1064 } 1065 1066 if (mValues3.size() != 0) { 1067 Uri dataUri = findFirstDataRow(rawContactId, Note.CONTENT_ITEM_TYPE); 1068 if (dataUri != null) { 1069 mContactsProvider.updateInTransaction(dataUri, mValues3, null, null); 1070 } else { 1071 mValues3.put(Data.RAW_CONTACT_ID, rawContactId); 1072 mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues3); 1073 } 1074 } 1075 1076 if (values.containsKey(People.LAST_TIME_CONTACTED) && 1077 !values.containsKey(People.TIMES_CONTACTED)) { 1078 updateContactTime(rawContactId, values); 1079 } 1080 1081 return count; 1082 } 1083 1084 private int updateOrganizations(long dataId, ContentValues values) { 1085 parseOrganizationValues(values); 1086 1087 return mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1088 Data._ID + "=" + dataId, null); 1089 } 1090 1091 private int updatePhones(long dataId, ContentValues values) { 1092 parsePhoneValues(values); 1093 1094 return mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1095 Data._ID + "=" + dataId, null); 1096 } 1097 1098 private int updateContactMethods(long dataId, ContentValues values) { 1099 int kind; 1100 1101 mDataMimetypeQuery.bindLong(1, dataId); 1102 long mimetype_id; 1103 try { 1104 mimetype_id = mDataMimetypeQuery.simpleQueryForLong(); 1105 } catch (SQLiteDoneException e) { 1106 // Data row not found 1107 return 0; 1108 } 1109 1110 if (mimetype_id == mMimetypeEmail) { 1111 kind = android.provider.Contacts.KIND_EMAIL; 1112 } else if (mimetype_id == mMimetypeIm) { 1113 kind = android.provider.Contacts.KIND_IM; 1114 } else if (mimetype_id == mMimetypePostal) { 1115 kind = android.provider.Contacts.KIND_POSTAL; 1116 } else { 1117 1118 // Non-legacy kind: return "Not found" 1119 return 0; 1120 } 1121 1122 parseContactMethodValues(kind, values); 1123 1124 return mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1125 Data._ID + "=" + dataId, null); 1126 } 1127 1128 private int updateExtensions(long dataId, ContentValues values) { 1129 parseExtensionValues(values); 1130 1131 return mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1132 Data._ID + "=" + dataId, null); 1133 } 1134 1135 private int updateGroups(long groupId, ContentValues values) { 1136 parseGroupValues(values); 1137 1138 return mContactsProvider.updateInTransaction(Groups.CONTENT_URI, mValues, 1139 Groups._ID + "=" + groupId, null); 1140 } 1141 1142 private int updateContactTime(Uri uri, ContentValues values) { 1143 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 1144 updateContactTime(rawContactId, values); 1145 return 1; 1146 } 1147 1148 private void updateContactTime(long rawContactId, ContentValues values) { 1149 long lastTimeContacted; 1150 if (values.containsKey(People.LAST_TIME_CONTACTED)) { 1151 lastTimeContacted = values.getAsLong(People.LAST_TIME_CONTACTED); 1152 } else { 1153 lastTimeContacted = System.currentTimeMillis(); 1154 } 1155 1156 // TODO check sanctions 1157 long contactId = mDbHelper.getContactId(rawContactId); 1158 SQLiteDatabase mDb = mDbHelper.getWritableDatabase(); 1159 mSelectionArgs2[0] = String.valueOf(lastTimeContacted); 1160 if (contactId != 0) { 1161 mSelectionArgs2[1] = String.valueOf(contactId); 1162 mDb.execSQL(CONTACTS_UPDATE_LASTTIMECONTACTED, mSelectionArgs2); 1163 // increment times_contacted column 1164 mSelectionArgs1[0] = String.valueOf(contactId); 1165 mDb.execSQL(ContactsProvider2.UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 1166 } 1167 mSelectionArgs2[1] = String.valueOf(rawContactId); 1168 mDb.execSQL(RAWCONTACTS_UPDATE_LASTTIMECONTACTED, mSelectionArgs2); 1169 // increment times_contacted column 1170 mSelectionArgs1[0] = String.valueOf(contactId); 1171 mDb.execSQL(ContactsProvider2.UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 1172 } 1173 1174 private int updatePhoto(long rawContactId, ContentValues values) { 1175 1176 // TODO check sanctions 1177 1178 int count; 1179 1180 long dataId = findFirstDataId(rawContactId, Photo.CONTENT_ITEM_TYPE); 1181 1182 mValues.clear(); 1183 byte[] bytes = values.getAsByteArray(android.provider.Contacts.Photos.DATA); 1184 mValues.put(Photo.PHOTO, bytes); 1185 1186 if (dataId == -1) { 1187 mValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 1188 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 1189 Uri dataUri = mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 1190 dataId = ContentUris.parseId(dataUri); 1191 count = 1; 1192 } else { 1193 Uri dataUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId); 1194 count = mContactsProvider.updateInTransaction(dataUri, mValues, null, null); 1195 } 1196 1197 updateLegacyPhotoData(rawContactId, dataId, values); 1198 1199 return count; 1200 } 1201 1202 private int updatePhotoByDataId(long dataId, ContentValues values) { 1203 1204 mDataRawContactIdQuery.bindLong(1, dataId); 1205 long rawContactId; 1206 1207 try { 1208 rawContactId = mDataRawContactIdQuery.simpleQueryForLong(); 1209 } catch (SQLiteDoneException e) { 1210 // Data row not found 1211 return 0; 1212 } 1213 1214 if (values.containsKey(android.provider.Contacts.Photos.DATA)) { 1215 byte[] bytes = values.getAsByteArray(android.provider.Contacts.Photos.DATA); 1216 mValues.clear(); 1217 mValues.put(Photo.PHOTO, bytes); 1218 mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1219 Data._ID + "=" + dataId, null); 1220 } 1221 1222 updateLegacyPhotoData(rawContactId, dataId, values); 1223 1224 return 1; 1225 } 1226 1227 private void updateLegacyPhotoData(long rawContactId, long dataId, ContentValues values) { 1228 mValues.clear(); 1229 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.LOCAL_VERSION, 1230 values, android.provider.Contacts.Photos.LOCAL_VERSION); 1231 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.DOWNLOAD_REQUIRED, 1232 values, android.provider.Contacts.Photos.DOWNLOAD_REQUIRED); 1233 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.EXISTS_ON_SERVER, 1234 values, android.provider.Contacts.Photos.EXISTS_ON_SERVER); 1235 ContactsDatabaseHelper.copyStringValue(mValues, LegacyPhotoData.SYNC_ERROR, 1236 values, android.provider.Contacts.Photos.SYNC_ERROR); 1237 1238 int updated = mContactsProvider.updateInTransaction(Data.CONTENT_URI, mValues, 1239 Data.MIMETYPE + "='" + LegacyPhotoData.CONTENT_ITEM_TYPE + "'" 1240 + " AND " + Data.RAW_CONTACT_ID + "=" + rawContactId 1241 + " AND " + LegacyPhotoData.PHOTO_DATA_ID + "=" + dataId, null); 1242 if (updated == 0) { 1243 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 1244 mValues.put(Data.MIMETYPE, LegacyPhotoData.CONTENT_ITEM_TYPE); 1245 mValues.put(LegacyPhotoData.PHOTO_DATA_ID, dataId); 1246 mContactsProvider.insertInTransaction(Data.CONTENT_URI, mValues); 1247 } 1248 } 1249 1250 private int updateSettings(ContentValues values) { 1251 SQLiteDatabase db = mDbHelper.getWritableDatabase(); 1252 String accountName = values.getAsString(android.provider.Contacts.Settings._SYNC_ACCOUNT); 1253 String accountType = 1254 values.getAsString(android.provider.Contacts.Settings._SYNC_ACCOUNT_TYPE); 1255 String key = values.getAsString(android.provider.Contacts.Settings.KEY); 1256 if (key == null) { 1257 throw new IllegalArgumentException("you must specify the key when updating settings"); 1258 } 1259 updateSetting(db, accountName, accountType, values); 1260 if (key.equals(android.provider.Contacts.Settings.SYNC_EVERYTHING)) { 1261 mValues.clear(); 1262 mValues.put(Settings.SHOULD_SYNC, 1263 values.getAsInteger(android.provider.Contacts.Settings.VALUE)); 1264 String selection; 1265 String[] selectionArgs; 1266 if (accountName != null && accountType != null) { 1267 1268 selectionArgs = new String[]{accountName, accountType}; 1269 selection = Settings.ACCOUNT_NAME + "=?" 1270 + " AND " + Settings.ACCOUNT_TYPE + "=?" 1271 + " AND " + Settings.DATA_SET + " IS NULL"; 1272 } else { 1273 selectionArgs = null; 1274 selection = Settings.ACCOUNT_NAME + " IS NULL" 1275 + " AND " + Settings.ACCOUNT_TYPE + " IS NULL" 1276 + " AND " + Settings.DATA_SET + " 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 " + ContactsContract.Settings.DATA_SET + " IS NULL" + 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 + 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 qb.setDistinct(true); 1753 } 1754 break; 1755 1756 case PEOPLE_PHONES: 1757 qb.setTables(LegacyTables.PHONES + " phones"); 1758 qb.setProjectionMap(sPhoneProjectionMap); 1759 applyRawContactsAccount(qb); 1760 qb.appendWhere(" AND " + android.provider.Contacts.Phones.PERSON_ID + "="); 1761 qb.appendWhere(uri.getPathSegments().get(1)); 1762 break; 1763 1764 case PEOPLE_PHONES_ID: 1765 qb.setTables(LegacyTables.PHONES + " phones"); 1766 qb.setProjectionMap(sPhoneProjectionMap); 1767 applyRawContactsAccount(qb); 1768 qb.appendWhere(" AND " + android.provider.Contacts.Phones.PERSON_ID + "="); 1769 qb.appendWhere(uri.getPathSegments().get(1)); 1770 qb.appendWhere(" AND " + android.provider.Contacts.Phones._ID + "="); 1771 qb.appendWhere(uri.getPathSegments().get(3)); 1772 break; 1773 1774 case EXTENSIONS: 1775 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1776 qb.setProjectionMap(sExtensionProjectionMap); 1777 applyRawContactsAccount(qb); 1778 break; 1779 1780 case EXTENSIONS_ID: 1781 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1782 qb.setProjectionMap(sExtensionProjectionMap); 1783 applyRawContactsAccount(qb); 1784 qb.appendWhere(" AND " + android.provider.Contacts.Extensions._ID + "="); 1785 qb.appendWhere(uri.getPathSegments().get(1)); 1786 break; 1787 1788 case PEOPLE_EXTENSIONS: 1789 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1790 qb.setProjectionMap(sExtensionProjectionMap); 1791 applyRawContactsAccount(qb); 1792 qb.appendWhere(" AND " + android.provider.Contacts.Extensions.PERSON_ID + "="); 1793 qb.appendWhere(uri.getPathSegments().get(1)); 1794 break; 1795 1796 case PEOPLE_EXTENSIONS_ID: 1797 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1798 qb.setProjectionMap(sExtensionProjectionMap); 1799 applyRawContactsAccount(qb); 1800 qb.appendWhere(" AND " + android.provider.Contacts.Extensions.PERSON_ID + "="); 1801 qb.appendWhere(uri.getPathSegments().get(1)); 1802 qb.appendWhere(" AND " + android.provider.Contacts.Extensions._ID + "="); 1803 qb.appendWhere(uri.getPathSegments().get(3)); 1804 break; 1805 1806 case GROUPS: 1807 qb.setTables(LegacyTables.GROUPS + " groups"); 1808 qb.setProjectionMap(sGroupProjectionMap); 1809 applyGroupAccount(qb); 1810 break; 1811 1812 case GROUPS_ID: 1813 qb.setTables(LegacyTables.GROUPS + " groups"); 1814 qb.setProjectionMap(sGroupProjectionMap); 1815 applyGroupAccount(qb); 1816 qb.appendWhere(" AND " + android.provider.Contacts.Groups._ID + "="); 1817 qb.appendWhere(uri.getPathSegments().get(1)); 1818 break; 1819 1820 case GROUPMEMBERSHIP: 1821 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1822 qb.setProjectionMap(sGroupMembershipProjectionMap); 1823 applyRawContactsAccount(qb); 1824 break; 1825 1826 case GROUPMEMBERSHIP_ID: 1827 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1828 qb.setProjectionMap(sGroupMembershipProjectionMap); 1829 applyRawContactsAccount(qb); 1830 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership._ID + "="); 1831 qb.appendWhere(uri.getPathSegments().get(1)); 1832 break; 1833 1834 case PEOPLE_GROUPMEMBERSHIP: 1835 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1836 qb.setProjectionMap(sGroupMembershipProjectionMap); 1837 applyRawContactsAccount(qb); 1838 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership.PERSON_ID + "="); 1839 qb.appendWhere(uri.getPathSegments().get(1)); 1840 break; 1841 1842 case PEOPLE_GROUPMEMBERSHIP_ID: 1843 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1844 qb.setProjectionMap(sGroupMembershipProjectionMap); 1845 applyRawContactsAccount(qb); 1846 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership.PERSON_ID + "="); 1847 qb.appendWhere(uri.getPathSegments().get(1)); 1848 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership._ID + "="); 1849 qb.appendWhere(uri.getPathSegments().get(3)); 1850 break; 1851 1852 case PEOPLE_PHOTO: 1853 qb.setTables(LegacyTables.PHOTOS + " photos"); 1854 qb.setProjectionMap(sPhotoProjectionMap); 1855 applyRawContactsAccount(qb); 1856 qb.appendWhere(" AND " + android.provider.Contacts.Photos.PERSON_ID + "="); 1857 qb.appendWhere(uri.getPathSegments().get(1)); 1858 limit = "1"; 1859 break; 1860 1861 case PHOTOS: 1862 qb.setTables(LegacyTables.PHOTOS + " photos"); 1863 qb.setProjectionMap(sPhotoProjectionMap); 1864 applyRawContactsAccount(qb); 1865 break; 1866 1867 case PHOTOS_ID: 1868 qb.setTables(LegacyTables.PHOTOS + " photos"); 1869 qb.setProjectionMap(sPhotoProjectionMap); 1870 applyRawContactsAccount(qb); 1871 qb.appendWhere(" AND " + android.provider.Contacts.Photos._ID + "="); 1872 qb.appendWhere(uri.getPathSegments().get(1)); 1873 break; 1874 1875 case SEARCH_SUGGESTIONS: 1876 return mGlobalSearchSupport.handleSearchSuggestionsQuery( 1877 db, uri, projection, limit); 1878 1879 case SEARCH_SHORTCUT: { 1880 String lookupKey = uri.getLastPathSegment(); 1881 String filter = ContactsProvider2.getQueryParameter(uri, "filter"); 1882 return mGlobalSearchSupport.handleSearchShortcutRefresh( 1883 db, projection, lookupKey, filter); 1884 } 1885 1886 case LIVE_FOLDERS_PEOPLE: 1887 return mContactsProvider.query(LIVE_FOLDERS_CONTACTS_URI, 1888 projection, selection, selectionArgs, sortOrder); 1889 1890 case LIVE_FOLDERS_PEOPLE_WITH_PHONES: 1891 return mContactsProvider.query(LIVE_FOLDERS_CONTACTS_WITH_PHONES_URI, 1892 projection, selection, selectionArgs, sortOrder); 1893 1894 case LIVE_FOLDERS_PEOPLE_FAVORITES: 1895 return mContactsProvider.query(LIVE_FOLDERS_CONTACTS_FAVORITES_URI, 1896 projection, selection, selectionArgs, sortOrder); 1897 1898 case LIVE_FOLDERS_PEOPLE_GROUP_NAME: 1899 return mContactsProvider.query(Uri.withAppendedPath(LIVE_FOLDERS_CONTACTS_URI, 1900 Uri.encode(uri.getLastPathSegment())), 1901 projection, selection, selectionArgs, sortOrder); 1902 1903 case DELETED_PEOPLE: 1904 case DELETED_GROUPS: 1905 throw new UnsupportedOperationException(mDbHelper.exceptionMessage(uri)); 1906 1907 case SETTINGS: 1908 copySettingsToLegacySettings(); 1909 qb.setTables(LegacyTables.SETTINGS); 1910 break; 1911 1912 default: 1913 throw new IllegalArgumentException(mDbHelper.exceptionMessage(uri)); 1914 } 1915 1916 // Perform the query and set the notification uri 1917 final Cursor c = qb.query(db, projection, selection, selectionArgs, 1918 groupBy, null, sortOrder, limit); 1919 if (c != null) { 1920 c.setNotificationUri(mContext.getContentResolver(), 1921 android.provider.Contacts.CONTENT_URI); 1922 } 1923 return c; 1924 } 1925 1926 private void applyRawContactsAccount(SQLiteQueryBuilder qb) { 1927 StringBuilder sb = new StringBuilder(); 1928 appendRawContactsAccount(sb); 1929 qb.appendWhere(sb.toString()); 1930 } 1931 1932 private void appendRawContactsAccount(StringBuilder sb) { 1933 if (mAccount != null) { 1934 sb.append(RawContacts.ACCOUNT_NAME + "="); 1935 DatabaseUtils.appendEscapedSQLString(sb, mAccount.name); 1936 sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 1937 DatabaseUtils.appendEscapedSQLString(sb, mAccount.type); 1938 } else { 1939 sb.append(RawContacts.ACCOUNT_NAME + " IS NULL" + 1940 " AND " + RawContacts.ACCOUNT_TYPE + " IS NULL"); 1941 } 1942 } 1943 1944 private void applyGroupAccount(SQLiteQueryBuilder qb) { 1945 StringBuilder sb = new StringBuilder(); 1946 appendGroupAccount(sb); 1947 qb.appendWhere(sb.toString()); 1948 } 1949 1950 private void appendGroupAccount(StringBuilder sb) { 1951 if (mAccount != null) { 1952 sb.append(Groups.ACCOUNT_NAME + "="); 1953 DatabaseUtils.appendEscapedSQLString(sb, mAccount.name); 1954 sb.append(" AND " + Groups.ACCOUNT_TYPE + "="); 1955 DatabaseUtils.appendEscapedSQLString(sb, mAccount.type); 1956 } else { 1957 sb.append(Groups.ACCOUNT_NAME + " IS NULL" + 1958 " AND " + Groups.ACCOUNT_TYPE + " IS NULL"); 1959 } 1960 } 1961 1962 /** 1963 * Build a WHERE clause that restricts the query to match people that are a member of 1964 * a group with a particular name. The projection map of the query must include 1965 * {@link People#_ID}. 1966 * 1967 * @param groupName The name of the group 1968 * @return The where clause. 1969 */ 1970 private String buildGroupNameMatchWhereClause(String groupName) { 1971 return "people._id IN " 1972 + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 1973 + " FROM " + Tables.DATA_JOIN_MIMETYPES 1974 + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE 1975 + "' AND " + GroupMembership.GROUP_ROW_ID + "=" 1976 + "(SELECT " + Tables.GROUPS + "." + Groups._ID 1977 + " FROM " + Tables.GROUPS 1978 + " WHERE " + Groups.TITLE + "=" 1979 + DatabaseUtils.sqlEscapeString(groupName) + "))"; 1980 } 1981 1982 /** 1983 * Build a WHERE clause that restricts the query to match people that are a member of 1984 * a group with a particular system id. The projection map of the query must include 1985 * {@link People#_ID}. 1986 * 1987 * @param groupName The name of the group 1988 * @return The where clause. 1989 */ 1990 private String buildGroupSystemIdMatchWhereClause(String systemId) { 1991 return "people._id IN " 1992 + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 1993 + " FROM " + Tables.DATA_JOIN_MIMETYPES 1994 + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE 1995 + "' AND " + GroupMembership.GROUP_ROW_ID + "=" 1996 + "(SELECT " + Tables.GROUPS + "." + Groups._ID 1997 + " FROM " + Tables.GROUPS 1998 + " WHERE " + Groups.SYSTEM_ID + "=" 1999 + DatabaseUtils.sqlEscapeString(systemId) + "))"; 2000 } 2001 2002 private String getRawContactsByFilterAsNestedQuery(String filterParam) { 2003 StringBuilder sb = new StringBuilder(); 2004 String normalizedName = NameNormalizer.normalize(filterParam); 2005 if (TextUtils.isEmpty(normalizedName)) { 2006 // Effectively an empty IN clause - SQL syntax does not allow an actual empty list here 2007 sb.append("(0)"); 2008 } else { 2009 sb.append("(" + 2010 "SELECT " + NameLookupColumns.RAW_CONTACT_ID + 2011 " FROM " + Tables.NAME_LOOKUP + 2012 " WHERE " + NameLookupColumns.NORMALIZED_NAME + 2013 " GLOB '"); 2014 // Should not use a "?" argument placeholder here, because 2015 // that would prevent the SQL optimizer from using the index on NORMALIZED_NAME. 2016 sb.append(normalizedName); 2017 sb.append("*' AND " + NameLookupColumns.NAME_TYPE + " IN (" 2018 + NameLookupType.NAME_COLLATION_KEY + "," 2019 + NameLookupType.NICKNAME); 2020 if (true) { 2021 sb.append("," + NameLookupType.EMAIL_BASED_NICKNAME); 2022 } 2023 sb.append("))"); 2024 } 2025 return sb.toString(); 2026 } 2027 2028 /** 2029 * Called when a change has been made. 2030 * 2031 * @param uri the uri that the change was made to 2032 */ 2033 private void onChange(Uri uri) { 2034 mContext.getContentResolver().notifyChange(android.provider.Contacts.CONTENT_URI, null); 2035 } 2036 2037 public String getType(Uri uri) { 2038 int match = sUriMatcher.match(uri); 2039 switch (match) { 2040 case EXTENSIONS: 2041 case PEOPLE_EXTENSIONS: 2042 return Extensions.CONTENT_TYPE; 2043 case EXTENSIONS_ID: 2044 case PEOPLE_EXTENSIONS_ID: 2045 return Extensions.CONTENT_ITEM_TYPE; 2046 case PEOPLE: 2047 return "vnd.android.cursor.dir/person"; 2048 case PEOPLE_ID: 2049 return "vnd.android.cursor.item/person"; 2050 case PEOPLE_PHONES: 2051 return "vnd.android.cursor.dir/phone"; 2052 case PEOPLE_PHONES_ID: 2053 return "vnd.android.cursor.item/phone"; 2054 case PEOPLE_CONTACTMETHODS: 2055 return "vnd.android.cursor.dir/contact-methods"; 2056 case PEOPLE_CONTACTMETHODS_ID: 2057 return getContactMethodType(uri); 2058 case PHONES: 2059 return "vnd.android.cursor.dir/phone"; 2060 case PHONES_ID: 2061 return "vnd.android.cursor.item/phone"; 2062 case PHONES_FILTER: 2063 return "vnd.android.cursor.dir/phone"; 2064 case PHOTOS_ID: 2065 return "vnd.android.cursor.item/photo"; 2066 case PHOTOS: 2067 return "vnd.android.cursor.dir/photo"; 2068 case PEOPLE_PHOTO: 2069 return "vnd.android.cursor.item/photo"; 2070 case CONTACTMETHODS: 2071 return "vnd.android.cursor.dir/contact-methods"; 2072 case CONTACTMETHODS_ID: 2073 return getContactMethodType(uri); 2074 case ORGANIZATIONS: 2075 return "vnd.android.cursor.dir/organizations"; 2076 case ORGANIZATIONS_ID: 2077 return "vnd.android.cursor.item/organization"; 2078 case SEARCH_SUGGESTIONS: 2079 return SearchManager.SUGGEST_MIME_TYPE; 2080 case SEARCH_SHORTCUT: 2081 return SearchManager.SHORTCUT_MIME_TYPE; 2082 default: 2083 throw new IllegalArgumentException(mDbHelper.exceptionMessage(uri)); 2084 } 2085 } 2086 2087 private String getContactMethodType(Uri url) { 2088 String mime = null; 2089 2090 Cursor c = query(url, new String[] {ContactMethods.KIND}, null, null, null, null); 2091 if (c != null) { 2092 try { 2093 if (c.moveToFirst()) { 2094 int kind = c.getInt(0); 2095 switch (kind) { 2096 case android.provider.Contacts.KIND_EMAIL: 2097 mime = "vnd.android.cursor.item/email"; 2098 break; 2099 2100 case android.provider.Contacts.KIND_IM: 2101 mime = "vnd.android.cursor.item/jabber-im"; 2102 break; 2103 2104 case android.provider.Contacts.KIND_POSTAL: 2105 mime = "vnd.android.cursor.item/postal-address"; 2106 break; 2107 } 2108 } 2109 } finally { 2110 c.close(); 2111 } 2112 } 2113 return mime; 2114 } 2115} 2116