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