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