LegacyApiSupport.java revision 5dec8cf5a992bac38c0e81d744fc77d748e926aa
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.OpenHelper.DataColumns; 19import com.android.providers.contacts.OpenHelper.ExtensionsColumns; 20import com.android.providers.contacts.OpenHelper.GroupsColumns; 21import com.android.providers.contacts.OpenHelper.MimetypesColumns; 22import com.android.providers.contacts.OpenHelper.PhoneColumns; 23import com.android.providers.contacts.OpenHelper.PresenceColumns; 24import com.android.providers.contacts.OpenHelper.RawContactsColumns; 25import com.android.providers.contacts.OpenHelper.Tables; 26 27import android.accounts.Account; 28import android.app.SearchManager; 29import android.content.ContentUris; 30import android.content.ContentValues; 31import android.content.Context; 32import android.content.UriMatcher; 33import android.database.Cursor; 34import android.database.DatabaseUtils; 35import android.database.sqlite.SQLiteDatabase; 36import android.database.sqlite.SQLiteQueryBuilder; 37import android.database.sqlite.SQLiteStatement; 38import android.net.Uri; 39import android.provider.Contacts; 40import android.provider.ContactsContract; 41import android.provider.Contacts.ContactMethods; 42import android.provider.Contacts.Extensions; 43import android.provider.Contacts.People; 44import android.provider.ContactsContract.Data; 45import android.provider.ContactsContract.Groups; 46import android.provider.ContactsContract.Presence; 47import android.provider.ContactsContract.RawContacts; 48import android.provider.ContactsContract.CommonDataKinds.Email; 49import android.provider.ContactsContract.CommonDataKinds.GroupMembership; 50import android.provider.ContactsContract.CommonDataKinds.Im; 51import android.provider.ContactsContract.CommonDataKinds.Note; 52import android.provider.ContactsContract.CommonDataKinds.Organization; 53import android.provider.ContactsContract.CommonDataKinds.Phone; 54import android.provider.ContactsContract.CommonDataKinds.Photo; 55import android.provider.ContactsContract.CommonDataKinds.StructuredName; 56import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 57 58import java.util.HashMap; 59 60public class LegacyApiSupport implements OpenHelper.Delegate { 61 62 private static final String TAG = "ContactsProviderV1"; 63 64 private static final String NON_EXISTENT_ACCOUNT_TYPE = "android.INVALID_ACCOUNT_TYPE"; 65 private static final String NON_EXISTENT_ACCOUNT_NAME = "invalid"; 66 67 private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 68 69 private static final int PEOPLE = 1; 70 private static final int PEOPLE_ID = 2; 71 private static final int PEOPLE_UPDATE_CONTACT_TIME = 3; 72 private static final int ORGANIZATIONS = 4; 73 private static final int ORGANIZATIONS_ID = 5; 74 private static final int PEOPLE_CONTACTMETHODS = 6; 75 private static final int PEOPLE_CONTACTMETHODS_ID = 7; 76 private static final int CONTACTMETHODS = 8; 77 private static final int CONTACTMETHODS_ID = 9; 78 private static final int PEOPLE_PHONES = 10; 79 private static final int PEOPLE_PHONES_ID = 11; 80 private static final int PHONES = 12; 81 private static final int PHONES_ID = 13; 82 private static final int EXTENSIONS = 14; 83 private static final int EXTENSIONS_ID = 15; 84 private static final int PEOPLE_EXTENSIONS = 16; 85 private static final int PEOPLE_EXTENSIONS_ID = 17; 86 private static final int GROUPS = 18; 87 private static final int GROUPS_ID = 19; 88 private static final int GROUPMEMBERSHIP = 20; 89 private static final int GROUPMEMBERSHIP_ID = 21; 90 private static final int PEOPLE_GROUPMEMBERSHIP = 22; 91 private static final int PEOPLE_GROUPMEMBERSHIP_ID = 23; 92 private static final int PEOPLE_PHOTO = 24; 93 private static final int PHOTOS = 25; 94 private static final int PHOTOS_ID = 26; 95 private static final int PEOPLE_FILTER = 29; 96 private static final int DELETED_PEOPLE = 30; 97 private static final int DELETED_GROUPS = 31; 98 private static final int SEARCH_SUGGESTIONS = 32; 99 private static final int SEARCH_SHORTCUT = 33; 100 private static final int PHONES_FILTER = 34; 101 102 private static final String PEOPLE_JOINS = 103 " LEFT OUTER JOIN data name ON (raw_contacts._id = name.raw_contact_id" 104 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = name.mimetype_id)" 105 + "='" + StructuredName.CONTENT_ITEM_TYPE + "')" 106 + " LEFT OUTER JOIN data organization ON (raw_contacts._id = organization.raw_contact_id" 107 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = organization.mimetype_id)" 108 + "='" + Organization.CONTENT_ITEM_TYPE + "' AND organization.is_primary)" 109 + " LEFT OUTER JOIN data email ON (raw_contacts._id = email.raw_contact_id" 110 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = email.mimetype_id)" 111 + "='" + Email.CONTENT_ITEM_TYPE + "' AND email.is_primary)" 112 + " LEFT OUTER JOIN data note ON (raw_contacts._id = note.raw_contact_id" 113 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = note.mimetype_id)" 114 + "='" + Note.CONTENT_ITEM_TYPE + "')" 115 + " LEFT OUTER JOIN data phone ON (raw_contacts._id = phone.raw_contact_id" 116 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = phone.mimetype_id)" 117 + "='" + Phone.CONTENT_ITEM_TYPE + "' AND phone.is_primary)"; 118 119 public static final String DATA_JOINS = 120 " JOIN mimetypes ON (mimetypes._id = data.mimetype_id)" 121 + " JOIN raw_contacts ON (raw_contacts._id = data.raw_contact_id)" 122 + PEOPLE_JOINS; 123 124 public static final String PRESENCE_JOINS = 125 " LEFT OUTER JOIN presence ON (" 126 + " presence.presence_id = (SELECT max(presence_id) FROM presence" 127 + " WHERE people._id = presence_raw_contact_id))"; 128 129 private static final String PHONETIC_NAME_SQL = "trim(trim(" 130 + "ifnull(name." + StructuredName.PHONETIC_GIVEN_NAME + ",' ')||' '||" 131 + "ifnull(name." + StructuredName.PHONETIC_MIDDLE_NAME + ",' '))||' '||" 132 + "ifnull(name." + StructuredName.PHONETIC_FAMILY_NAME + ",' ')) "; 133 134 private static final String CONTACT_METHOD_KIND_SQL = 135 "CAST ((CASE WHEN mimetype='" + Email.CONTENT_ITEM_TYPE + "'" 136 + " THEN " + android.provider.Contacts.KIND_EMAIL 137 + " ELSE" 138 + " (CASE WHEN mimetype='" + Im.CONTENT_ITEM_TYPE +"'" 139 + " THEN " + android.provider.Contacts.KIND_IM 140 + " ELSE" 141 + " (CASE WHEN mimetype='" + StructuredPostal.CONTENT_ITEM_TYPE + "'" 142 + " THEN " + android.provider.Contacts.KIND_POSTAL 143 + " ELSE" 144 + " NULL" 145 + " END)" 146 + " END)" 147 + " END) AS INTEGER)"; 148 149 private static final String IM_PROTOCOL_SQL = 150 "(CASE WHEN " + Presence.PROTOCOL + "=" + Im.PROTOCOL_CUSTOM 151 + " THEN 'custom:'||" + Presence.CUSTOM_PROTOCOL 152 + " ELSE 'pre:'||" + Presence.PROTOCOL 153 + " END)"; 154 155 private static String CONTACT_METHOD_DATA_SQL = 156 "(CASE WHEN " + Data.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'" 157 + " THEN (CASE WHEN " + Tables.DATA + "." + Im.PROTOCOL + "=" + Im.PROTOCOL_CUSTOM 158 + " THEN 'custom:'||" + Tables.DATA + "." + Im.CUSTOM_PROTOCOL 159 + " ELSE 'pre:'||" + Tables.DATA + "." + Im.PROTOCOL 160 + " END)" 161 + " ELSE " + DataColumns.CONCRETE_DATA2 162 + " END)"; 163 164 165 public interface LegacyTables { 166 public static final String PEOPLE = "view_v1_people"; 167 public static final String PEOPLE_JOIN_PRESENCE = "view_v1_people people " + PRESENCE_JOINS; 168 public static final String GROUPS = "view_v1_groups"; 169 public static final String ORGANIZATIONS = "view_v1_organizations"; 170 public static final String CONTACT_METHODS = "view_v1_contact_methods"; 171 public static final String PHONES = "view_v1_phones"; 172 public static final String EXTENSIONS = "view_v1_extensions"; 173 public static final String GROUP_MEMBERSHIP = "view_v1_group_membership"; 174 public static final String PHOTOS = "view_v1_photos"; 175 } 176 177 private static final String[] ORGANIZATION_MIME_TYPES = new String[] { 178 Organization.CONTENT_ITEM_TYPE 179 }; 180 181 private static final String[] CONTACT_METHOD_MIME_TYPES = new String[] { 182 Email.CONTENT_ITEM_TYPE, 183 Im.CONTENT_ITEM_TYPE, 184 StructuredPostal.CONTENT_ITEM_TYPE, 185 }; 186 187 private static final String[] PHONE_MIME_TYPES = new String[] { 188 Phone.CONTENT_ITEM_TYPE 189 }; 190 191 private interface PhotoQuery { 192 String[] COLUMNS = { Data._ID }; 193 194 int _ID = 0; 195 } 196 197 /** 198 * A custom data row that is used to store legacy photo data fields no 199 * longer directly supported by the API. 200 */ 201 private interface LegacyPhotoData { 202 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo_v1_extras"; 203 204 public static final String PHOTO_DATA_ID = Data.DATA1; 205 public static final String LOCAL_VERSION = Data.DATA2; 206 public static final String DOWNLOAD_REQUIRED = Data.DATA3; 207 public static final String EXISTS_ON_SERVER = Data.DATA4; 208 public static final String SYNC_ERROR = Data.DATA5; 209 } 210 211 public static final String LEGACY_PHOTO_JOIN = 212 " LEFT OUTER JOIN data legacy_photo ON (raw_contacts._id = legacy_photo.raw_contact_id" 213 + " AND (SELECT mimetype FROM mimetypes WHERE mimetypes._id = legacy_photo.mimetype_id)" 214 + "='" + LegacyPhotoData.CONTENT_ITEM_TYPE + "'" 215 + " AND " + DataColumns.CONCRETE_ID + " = legacy_photo." + LegacyPhotoData.PHOTO_DATA_ID 216 + ")"; 217 218 private static final HashMap<String, String> sPeopleProjectionMap; 219 private static final HashMap<String, String> sOrganizationProjectionMap; 220 private static final HashMap<String, String> sContactMethodProjectionMap; 221 private static final HashMap<String, String> sPhoneProjectionMap; 222 private static final HashMap<String, String> sExtensionProjectionMap; 223 private static final HashMap<String, String> sGroupProjectionMap; 224 private static final HashMap<String, String> sGroupMembershipProjectionMap; 225 private static final HashMap<String, String> sPhotoProjectionMap; 226 227 228 static { 229 230 // Contacts URI matching table 231 UriMatcher matcher = sUriMatcher; 232 233 String authority = android.provider.Contacts.AUTHORITY; 234 matcher.addURI(authority, "extensions", EXTENSIONS); 235 matcher.addURI(authority, "extensions/#", EXTENSIONS_ID); 236 matcher.addURI(authority, "groups", GROUPS); 237 matcher.addURI(authority, "groups/#", GROUPS_ID); 238// matcher.addURI(authority, "groups/name/*/members", GROUP_NAME_MEMBERS); 239// matcher.addURI(authority, "groups/name/*/members/filter/*", 240// GROUP_NAME_MEMBERS_FILTER); 241// matcher.addURI(authority, "groups/system_id/*/members", GROUP_SYSTEM_ID_MEMBERS); 242// matcher.addURI(authority, "groups/system_id/*/members/filter/*", 243// GROUP_SYSTEM_ID_MEMBERS_FILTER); 244 matcher.addURI(authority, "groupmembership", GROUPMEMBERSHIP); 245 matcher.addURI(authority, "groupmembership/#", GROUPMEMBERSHIP_ID); 246// matcher.addURI(authority, "groupmembershipraw", GROUPMEMBERSHIP_RAW); 247 matcher.addURI(authority, "people", PEOPLE); 248// matcher.addURI(authority, "people/strequent", PEOPLE_STREQUENT); 249// matcher.addURI(authority, "people/strequent/filter/*", PEOPLE_STREQUENT_FILTER); 250 matcher.addURI(authority, "people/filter/*", PEOPLE_FILTER); 251// matcher.addURI(authority, "people/with_phones_filter/*", 252// PEOPLE_WITH_PHONES_FILTER); 253// matcher.addURI(authority, "people/with_email_or_im_filter/*", 254// PEOPLE_WITH_EMAIL_OR_IM_FILTER); 255 matcher.addURI(authority, "people/#", PEOPLE_ID); 256 matcher.addURI(authority, "people/#/extensions", PEOPLE_EXTENSIONS); 257 matcher.addURI(authority, "people/#/extensions/#", PEOPLE_EXTENSIONS_ID); 258 matcher.addURI(authority, "people/#/phones", PEOPLE_PHONES); 259 matcher.addURI(authority, "people/#/phones/#", PEOPLE_PHONES_ID); 260// matcher.addURI(authority, "people/#/phones_with_presence", 261// PEOPLE_PHONES_WITH_PRESENCE); 262 matcher.addURI(authority, "people/#/photo", PEOPLE_PHOTO); 263// matcher.addURI(authority, "people/#/photo/data", PEOPLE_PHOTO_DATA); 264 matcher.addURI(authority, "people/#/contact_methods", PEOPLE_CONTACTMETHODS); 265// matcher.addURI(authority, "people/#/contact_methods_with_presence", 266// PEOPLE_CONTACTMETHODS_WITH_PRESENCE); 267 matcher.addURI(authority, "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID); 268// matcher.addURI(authority, "people/#/organizations", PEOPLE_ORGANIZATIONS); 269// matcher.addURI(authority, "people/#/organizations/#", PEOPLE_ORGANIZATIONS_ID); 270 matcher.addURI(authority, "people/#/groupmembership", PEOPLE_GROUPMEMBERSHIP); 271 matcher.addURI(authority, "people/#/groupmembership/#", PEOPLE_GROUPMEMBERSHIP_ID); 272// matcher.addURI(authority, "people/raw", PEOPLE_RAW); 273// matcher.addURI(authority, "people/owner", PEOPLE_OWNER); 274 matcher.addURI(authority, "people/#/update_contact_time", 275 PEOPLE_UPDATE_CONTACT_TIME); 276 matcher.addURI(authority, "deleted_people", DELETED_PEOPLE); 277 matcher.addURI(authority, "deleted_groups", DELETED_GROUPS); 278 matcher.addURI(authority, "phones", PHONES); 279// matcher.addURI(authority, "phones_with_presence", PHONES_WITH_PRESENCE); 280 matcher.addURI(authority, "phones/filter/*", PHONES_FILTER); 281// matcher.addURI(authority, "phones/filter_name/*", PHONES_FILTER_NAME); 282// matcher.addURI(authority, "phones/mobile_filter_name/*", 283// PHONES_MOBILE_FILTER_NAME); 284 matcher.addURI(authority, "phones/#", PHONES_ID); 285 matcher.addURI(authority, "photos", PHOTOS); 286 matcher.addURI(authority, "photos/#", PHOTOS_ID); 287 matcher.addURI(authority, "contact_methods", CONTACTMETHODS); 288// matcher.addURI(authority, "contact_methods/email", CONTACTMETHODS_EMAIL); 289// matcher.addURI(authority, "contact_methods/email/*", CONTACTMETHODS_EMAIL_FILTER); 290 matcher.addURI(authority, "contact_methods/#", CONTACTMETHODS_ID); 291// matcher.addURI(authority, "contact_methods/with_presence", 292// CONTACTMETHODS_WITH_PRESENCE); 293 matcher.addURI(authority, "organizations", ORGANIZATIONS); 294 matcher.addURI(authority, "organizations/#", ORGANIZATIONS_ID); 295// matcher.addURI(authority, "voice_dialer_timestamp", VOICE_DIALER_TIMESTAMP); 296 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_QUERY, 297 SEARCH_SUGGESTIONS); 298 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 299 SEARCH_SUGGESTIONS); 300 matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/#", 301 SEARCH_SHORTCUT); 302// matcher.addURI(authority, "settings", SETTINGS); 303// 304// matcher.addURI(authority, "live_folders/people", LIVE_FOLDERS_PEOPLE); 305// matcher.addURI(authority, "live_folders/people/*", 306// LIVE_FOLDERS_PEOPLE_GROUP_NAME); 307// matcher.addURI(authority, "live_folders/people_with_phones", 308// LIVE_FOLDERS_PEOPLE_WITH_PHONES); 309// matcher.addURI(authority, "live_folders/favorites", 310// LIVE_FOLDERS_PEOPLE_FAVORITES); 311 312 313 HashMap<String, String> peopleProjectionMap = new HashMap<String, String>(); 314 peopleProjectionMap.put(People.NAME, People.NAME); 315 peopleProjectionMap.put(People.DISPLAY_NAME, People.DISPLAY_NAME); 316 peopleProjectionMap.put(People.PHONETIC_NAME, People.PHONETIC_NAME); 317 peopleProjectionMap.put(People.NOTES, People.NOTES); 318 peopleProjectionMap.put(People.TIMES_CONTACTED, People.TIMES_CONTACTED); 319 peopleProjectionMap.put(People.LAST_TIME_CONTACTED, People.LAST_TIME_CONTACTED); 320 peopleProjectionMap.put(People.CUSTOM_RINGTONE, People.CUSTOM_RINGTONE); 321 peopleProjectionMap.put(People.SEND_TO_VOICEMAIL, People.SEND_TO_VOICEMAIL); 322 peopleProjectionMap.put(People.STARRED, People.STARRED); 323 324 sPeopleProjectionMap = new HashMap<String, String>(peopleProjectionMap); 325 sPeopleProjectionMap.put(People._ID, People._ID); 326 sPeopleProjectionMap.put(People.PRIMARY_ORGANIZATION_ID, People.PRIMARY_ORGANIZATION_ID); 327 sPeopleProjectionMap.put(People.PRIMARY_EMAIL_ID, People.PRIMARY_EMAIL_ID); 328 sPeopleProjectionMap.put(People.PRIMARY_PHONE_ID, People.PRIMARY_PHONE_ID); 329 sPeopleProjectionMap.put(People.NUMBER, People.NUMBER); 330 sPeopleProjectionMap.put(People.TYPE, People.TYPE); 331 sPeopleProjectionMap.put(People.LABEL, People.LABEL); 332 sPeopleProjectionMap.put(People.NUMBER_KEY, People.NUMBER_KEY); 333 sPeopleProjectionMap.put(People.IM_PROTOCOL, IM_PROTOCOL_SQL + " AS " + People.IM_PROTOCOL); 334 sPeopleProjectionMap.put(People.IM_HANDLE, People.IM_HANDLE); 335 sPeopleProjectionMap.put(People.IM_ACCOUNT, People.IM_ACCOUNT); 336 sPeopleProjectionMap.put(People.PRESENCE_STATUS, People.PRESENCE_STATUS); 337 sPeopleProjectionMap.put(People.PRESENCE_CUSTOM_STATUS, People.PRESENCE_CUSTOM_STATUS); 338 339 sOrganizationProjectionMap = new HashMap<String, String>(); 340 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations._ID, 341 android.provider.Contacts.Organizations._ID); 342 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.PERSON_ID, 343 android.provider.Contacts.Organizations.PERSON_ID); 344 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.ISPRIMARY, 345 android.provider.Contacts.Organizations.ISPRIMARY); 346 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.COMPANY, 347 android.provider.Contacts.Organizations.COMPANY); 348 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.TYPE, 349 android.provider.Contacts.Organizations.TYPE); 350 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.LABEL, 351 android.provider.Contacts.Organizations.LABEL); 352 sOrganizationProjectionMap.put(android.provider.Contacts.Organizations.TITLE, 353 android.provider.Contacts.Organizations.TITLE); 354 355 sContactMethodProjectionMap = new HashMap<String, String>(peopleProjectionMap); 356 sContactMethodProjectionMap.put(ContactMethods._ID, ContactMethods._ID); 357 sContactMethodProjectionMap.put(ContactMethods.PERSON_ID, ContactMethods.PERSON_ID); 358 sContactMethodProjectionMap.put(ContactMethods.KIND, ContactMethods.KIND); 359 sContactMethodProjectionMap.put(ContactMethods.ISPRIMARY, ContactMethods.ISPRIMARY); 360 sContactMethodProjectionMap.put(ContactMethods.TYPE, ContactMethods.TYPE); 361 sContactMethodProjectionMap.put(ContactMethods.DATA, ContactMethods.DATA); 362 sContactMethodProjectionMap.put(ContactMethods.LABEL, ContactMethods.LABEL); 363 sContactMethodProjectionMap.put(ContactMethods.AUX_DATA, ContactMethods.AUX_DATA); 364 365 sPhoneProjectionMap = new HashMap<String, String>(peopleProjectionMap); 366 sPhoneProjectionMap.put(android.provider.Contacts.Phones._ID, 367 android.provider.Contacts.Phones._ID); 368 sPhoneProjectionMap.put(android.provider.Contacts.Phones.PERSON_ID, 369 android.provider.Contacts.Phones.PERSON_ID); 370 sPhoneProjectionMap.put(android.provider.Contacts.Phones.ISPRIMARY, 371 android.provider.Contacts.Phones.ISPRIMARY); 372 sPhoneProjectionMap.put(android.provider.Contacts.Phones.NUMBER, 373 android.provider.Contacts.Phones.NUMBER); 374 sPhoneProjectionMap.put(android.provider.Contacts.Phones.TYPE, 375 android.provider.Contacts.Phones.TYPE); 376 sPhoneProjectionMap.put(android.provider.Contacts.Phones.LABEL, 377 android.provider.Contacts.Phones.LABEL); 378 sPhoneProjectionMap.put(android.provider.Contacts.Phones.NUMBER_KEY, 379 android.provider.Contacts.Phones.NUMBER_KEY); 380 381 sExtensionProjectionMap = new HashMap<String, String>(); 382 sExtensionProjectionMap.put(android.provider.Contacts.Extensions._ID, 383 android.provider.Contacts.Extensions._ID); 384 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.PERSON_ID, 385 android.provider.Contacts.Extensions.PERSON_ID); 386 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.NAME, 387 android.provider.Contacts.Extensions.NAME); 388 sExtensionProjectionMap.put(android.provider.Contacts.Extensions.VALUE, 389 android.provider.Contacts.Extensions.VALUE); 390 391 sGroupProjectionMap = new HashMap<String, String>(); 392 sGroupProjectionMap.put(android.provider.Contacts.Groups._ID, 393 android.provider.Contacts.Groups._ID); 394 sGroupProjectionMap.put(android.provider.Contacts.Groups.NAME, 395 android.provider.Contacts.Groups.NAME); 396 sGroupProjectionMap.put(android.provider.Contacts.Groups.NOTES, 397 android.provider.Contacts.Groups.NOTES); 398 sGroupProjectionMap.put(android.provider.Contacts.Groups.SYSTEM_ID, 399 android.provider.Contacts.Groups.SYSTEM_ID); 400 401 sGroupMembershipProjectionMap = new HashMap<String, String>(); 402 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership._ID, 403 android.provider.Contacts.GroupMembership._ID); 404 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership.PERSON_ID, 405 android.provider.Contacts.GroupMembership.PERSON_ID); 406 sGroupMembershipProjectionMap.put(android.provider.Contacts.GroupMembership.GROUP_ID, 407 android.provider.Contacts.GroupMembership.GROUP_ID); 408 409 sPhotoProjectionMap = new HashMap<String, String>(); 410 sPhotoProjectionMap.put(android.provider.Contacts.Photos._ID, 411 android.provider.Contacts.Photos._ID); 412 sPhotoProjectionMap.put(android.provider.Contacts.Photos.PERSON_ID, 413 android.provider.Contacts.Photos.PERSON_ID); 414 sPhotoProjectionMap.put(android.provider.Contacts.Photos.DATA, 415 android.provider.Contacts.Photos.DATA); 416 sPhotoProjectionMap.put(android.provider.Contacts.Photos.LOCAL_VERSION, 417 android.provider.Contacts.Photos.LOCAL_VERSION); 418 sPhotoProjectionMap.put(android.provider.Contacts.Photos.DOWNLOAD_REQUIRED, 419 android.provider.Contacts.Photos.DOWNLOAD_REQUIRED); 420 sPhotoProjectionMap.put(android.provider.Contacts.Photos.EXISTS_ON_SERVER, 421 android.provider.Contacts.Photos.EXISTS_ON_SERVER); 422 sPhotoProjectionMap.put(android.provider.Contacts.Photos.SYNC_ERROR, 423 android.provider.Contacts.Photos.SYNC_ERROR); 424 } 425 426 private final Context mContext; 427 private final OpenHelper mOpenHelper; 428 private final ContactsProvider2 mContactsProvider; 429 private final NameSplitter mPhoneticNameSplitter; 430 private final GlobalSearchSupport mGlobalSearchSupport; 431 432 /** Precompiled sql statement for incrementing times contacted for a contact */ 433 private final SQLiteStatement mLastTimeContactedUpdate; 434 435 private final ContentValues mValues = new ContentValues(); 436 private Account mAccount; 437 438 public LegacyApiSupport(Context context, OpenHelper openHelper, 439 ContactsProvider2 contactsProvider, GlobalSearchSupport globalSearchSupport) { 440 mContext = context; 441 mContactsProvider = contactsProvider; 442 mOpenHelper = openHelper; 443 mGlobalSearchSupport = globalSearchSupport; 444 mOpenHelper.setDelegate(this); 445 446 mPhoneticNameSplitter = new NameSplitter("", "", "", 447 context.getString(com.android.internal.R.string.common_name_conjunctions)); 448 449 SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 450 mLastTimeContactedUpdate = db.compileStatement("UPDATE " + Tables.RAW_CONTACTS + " SET " 451 + RawContacts.TIMES_CONTACTED + "=" 452 + RawContacts.TIMES_CONTACTED + "+1," 453 + RawContacts.LAST_TIME_CONTACTED + "=? WHERE " 454 + RawContacts._ID + "=?"); 455 } 456 457 private void ensureDefaultAccount() { 458 if (mAccount == null) { 459 mAccount = mContactsProvider.getDefaultAccount(); 460 if (mAccount == null) { 461 462 // This fall-through account will not match any data in the database, which 463 // is the expected behavior 464 mAccount = new Account(NON_EXISTENT_ACCOUNT_NAME, NON_EXISTENT_ACCOUNT_TYPE); 465 } 466 } 467 } 468 469 public void createDatabase(SQLiteDatabase db) { 470 471 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.PEOPLE + ";"); 472 db.execSQL("CREATE VIEW " + LegacyTables.PEOPLE + " AS SELECT " + 473 RawContactsColumns.CONCRETE_ID 474 + " AS " + android.provider.Contacts.People._ID + ", " + 475 "name." + StructuredName.DISPLAY_NAME 476 + " AS " + People.NAME + ", " + 477 Tables.RAW_CONTACTS + "." + RawContactsColumns.DISPLAY_NAME 478 + " AS " + People.DISPLAY_NAME + ", " + 479 PHONETIC_NAME_SQL 480 + " AS " + People.PHONETIC_NAME + " , " + 481 "note." + Note.NOTE 482 + " AS " + People.NOTES + ", " + 483 RawContacts.ACCOUNT_NAME + ", " + 484 RawContacts.ACCOUNT_TYPE + ", " + 485 Tables.RAW_CONTACTS + "." + RawContacts.TIMES_CONTACTED 486 + " AS " + People.TIMES_CONTACTED + ", " + 487 Tables.RAW_CONTACTS + "." + RawContacts.LAST_TIME_CONTACTED 488 + " AS " + People.LAST_TIME_CONTACTED + ", " + 489 Tables.RAW_CONTACTS + "." + RawContacts.CUSTOM_RINGTONE 490 + " AS " + People.CUSTOM_RINGTONE + ", " + 491 Tables.RAW_CONTACTS + "." + RawContacts.SEND_TO_VOICEMAIL 492 + " AS " + People.SEND_TO_VOICEMAIL + ", " + 493 Tables.RAW_CONTACTS + "." + RawContacts.STARRED 494 + " AS " + People.STARRED + ", " + 495 "organization." + Data._ID 496 + " AS " + People.PRIMARY_ORGANIZATION_ID + ", " + 497 "email." + Data._ID 498 + " AS " + People.PRIMARY_EMAIL_ID + ", " + 499 "phone." + Data._ID 500 + " AS " + People.PRIMARY_PHONE_ID + ", " + 501 "phone." + Phone.NUMBER 502 + " AS " + People.NUMBER + ", " + 503 "phone." + Phone.TYPE 504 + " AS " + People.TYPE + ", " + 505 "phone." + Phone.LABEL 506 + " AS " + People.LABEL + ", " + 507 "phone." + PhoneColumns.NORMALIZED_NUMBER 508 + " AS " + People.NUMBER_KEY + 509 " FROM " + Tables.RAW_CONTACTS + PEOPLE_JOINS + 510 " WHERE " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" 511 + " AND " + RawContacts.IS_RESTRICTED + "=0" + 512 ";"); 513 514 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.ORGANIZATIONS + ";"); 515 db.execSQL("CREATE VIEW " + LegacyTables.ORGANIZATIONS + " AS SELECT " + 516 DataColumns.CONCRETE_ID 517 + " AS " + android.provider.Contacts.Organizations._ID + ", " + 518 Data.RAW_CONTACT_ID 519 + " AS " + android.provider.Contacts.Organizations.PERSON_ID + ", " + 520 Data.IS_PRIMARY 521 + " AS " + android.provider.Contacts.Organizations.ISPRIMARY + ", " + 522 RawContacts.ACCOUNT_NAME + ", " + 523 RawContacts.ACCOUNT_TYPE + ", " + 524 Organization.COMPANY 525 + " AS " + android.provider.Contacts.Organizations.COMPANY + ", " + 526 Organization.TYPE 527 + " AS " + android.provider.Contacts.Organizations.TYPE + ", " + 528 Organization.LABEL 529 + " AS " + android.provider.Contacts.Organizations.LABEL + ", " + 530 Organization.TITLE 531 + " AS " + android.provider.Contacts.Organizations.TITLE + 532 " FROM " + Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS + 533 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 534 + Organization.CONTENT_ITEM_TYPE + "'" 535 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" 536 + " AND " + RawContacts.IS_RESTRICTED + "=0" + 537 ";"); 538 539 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.CONTACT_METHODS + ";"); 540 db.execSQL("CREATE VIEW " + LegacyTables.CONTACT_METHODS + " AS SELECT " + 541 DataColumns.CONCRETE_ID 542 + " AS " + ContactMethods._ID + ", " + 543 DataColumns.CONCRETE_RAW_CONTACT_ID 544 + " AS " + ContactMethods.PERSON_ID + ", " + 545 CONTACT_METHOD_KIND_SQL 546 + " AS " + ContactMethods.KIND + ", " + 547 DataColumns.CONCRETE_IS_PRIMARY 548 + " AS " + ContactMethods.ISPRIMARY + ", " + 549 DataColumns.CONCRETE_DATA1 550 + " AS " + ContactMethods.TYPE + ", " + 551 CONTACT_METHOD_DATA_SQL 552 + " AS " + ContactMethods.DATA + ", " + 553 DataColumns.CONCRETE_DATA3 554 + " AS " + ContactMethods.LABEL + ", " + 555 DataColumns.CONCRETE_DATA14 556 + " AS " + ContactMethods.AUX_DATA + ", " + 557 "name." + StructuredName.DISPLAY_NAME 558 + " AS " + ContactMethods.NAME + ", " + 559 Tables.RAW_CONTACTS + "." + RawContactsColumns.DISPLAY_NAME 560 + " AS " + ContactMethods.DISPLAY_NAME + ", " + 561 RawContacts.ACCOUNT_NAME + ", " + 562 RawContacts.ACCOUNT_TYPE + ", " + 563 PHONETIC_NAME_SQL 564 + " AS " + ContactMethods.PHONETIC_NAME + " , " + 565 "note." + Note.NOTE 566 + " AS " + ContactMethods.NOTES + ", " + 567 Tables.RAW_CONTACTS + "." + RawContacts.TIMES_CONTACTED 568 + " AS " + ContactMethods.TIMES_CONTACTED + ", " + 569 Tables.RAW_CONTACTS + "." + RawContacts.LAST_TIME_CONTACTED 570 + " AS " + ContactMethods.LAST_TIME_CONTACTED + ", " + 571 Tables.RAW_CONTACTS + "." + RawContacts.CUSTOM_RINGTONE 572 + " AS " + ContactMethods.CUSTOM_RINGTONE + ", " + 573 Tables.RAW_CONTACTS + "." + RawContacts.SEND_TO_VOICEMAIL 574 + " AS " + ContactMethods.SEND_TO_VOICEMAIL + ", " + 575 Tables.RAW_CONTACTS + "." + RawContacts.STARRED 576 + " AS " + ContactMethods.STARRED + 577 " FROM " + Tables.DATA + DATA_JOINS + 578 " WHERE " + ContactMethods.KIND + " IS NOT NULL" 579 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" 580 + " AND " + RawContacts.IS_RESTRICTED + "=0" + 581 ";"); 582 583 584 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.PHONES + ";"); 585 db.execSQL("CREATE VIEW " + LegacyTables.PHONES + " AS SELECT " + 586 DataColumns.CONCRETE_ID 587 + " AS " + android.provider.Contacts.Phones._ID + ", " + 588 DataColumns.CONCRETE_RAW_CONTACT_ID 589 + " AS " + android.provider.Contacts.Phones.PERSON_ID + ", " + 590 DataColumns.CONCRETE_IS_PRIMARY 591 + " AS " + android.provider.Contacts.Phones.ISPRIMARY + ", " + 592 Tables.DATA + "." + Phone.NUMBER 593 + " AS " + android.provider.Contacts.Phones.NUMBER + ", " + 594 Tables.DATA + "." + Phone.TYPE 595 + " AS " + android.provider.Contacts.Phones.TYPE + ", " + 596 Tables.DATA + "." + Phone.LABEL 597 + " AS " + android.provider.Contacts.Phones.LABEL + ", " + 598 PhoneColumns.CONCRETE_NORMALIZED_NUMBER 599 + " AS " + android.provider.Contacts.Phones.NUMBER_KEY + ", " + 600 "name." + StructuredName.DISPLAY_NAME 601 + " AS " + android.provider.Contacts.Phones.NAME + ", " + 602 Tables.RAW_CONTACTS + "." + RawContactsColumns.DISPLAY_NAME 603 + " AS " + android.provider.Contacts.Phones.DISPLAY_NAME + ", " + 604 RawContacts.ACCOUNT_NAME + ", " + 605 RawContacts.ACCOUNT_TYPE + ", " + 606 PHONETIC_NAME_SQL 607 + " AS " + android.provider.Contacts.Phones.PHONETIC_NAME + " , " + 608 "note." + Note.NOTE 609 + " AS " + android.provider.Contacts.Phones.NOTES + ", " + 610 Tables.RAW_CONTACTS + "." + RawContacts.TIMES_CONTACTED 611 + " AS " + android.provider.Contacts.Phones.TIMES_CONTACTED + ", " + 612 Tables.RAW_CONTACTS + "." + RawContacts.LAST_TIME_CONTACTED 613 + " AS " + android.provider.Contacts.Phones.LAST_TIME_CONTACTED + ", " + 614 Tables.RAW_CONTACTS + "." + RawContacts.CUSTOM_RINGTONE 615 + " AS " + android.provider.Contacts.Phones.CUSTOM_RINGTONE + ", " + 616 Tables.RAW_CONTACTS + "." + RawContacts.SEND_TO_VOICEMAIL 617 + " AS " + android.provider.Contacts.Phones.SEND_TO_VOICEMAIL + ", " + 618 Tables.RAW_CONTACTS + "." + RawContacts.STARRED 619 + " AS " + android.provider.Contacts.Phones.STARRED + 620 " FROM " + Tables.DATA + DATA_JOINS + 621 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 622 + Phone.CONTENT_ITEM_TYPE + "'" 623 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" 624 + " AND " + RawContacts.IS_RESTRICTED + "=0" + 625 ";"); 626 627 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.EXTENSIONS + ";"); 628 db.execSQL("CREATE VIEW " + LegacyTables.EXTENSIONS + " AS SELECT " + 629 DataColumns.CONCRETE_ID 630 + " AS " + android.provider.Contacts.Extensions._ID + ", " + 631 DataColumns.CONCRETE_RAW_CONTACT_ID 632 + " AS " + android.provider.Contacts.Extensions.PERSON_ID + ", " + 633 RawContacts.ACCOUNT_NAME + ", " + 634 RawContacts.ACCOUNT_TYPE + ", " + 635 ExtensionsColumns.NAME 636 + " AS " + android.provider.Contacts.Extensions.NAME + ", " + 637 ExtensionsColumns.VALUE 638 + " AS " + android.provider.Contacts.Extensions.VALUE + 639 " FROM " + Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS + 640 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 641 + android.provider.Contacts.Extensions.CONTENT_ITEM_TYPE + "'" 642 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" 643 + " AND " + RawContacts.IS_RESTRICTED + "=0" + 644 ";"); 645 646 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.GROUPS + ";"); 647 db.execSQL("CREATE VIEW " + LegacyTables.GROUPS + " AS SELECT " + 648 GroupsColumns.CONCRETE_ID + " AS " + android.provider.Contacts.Groups._ID + ", " + 649 Groups.ACCOUNT_NAME + ", " + 650 Groups.ACCOUNT_TYPE + ", " + 651 Groups.TITLE + " AS " + android.provider.Contacts.Groups.NAME + ", " + 652 Groups.NOTES + " AS " + android.provider.Contacts.Groups.NOTES + " , " + 653 Groups.SYSTEM_ID + " AS " + android.provider.Contacts.Groups.SYSTEM_ID + 654 " FROM " + Tables.GROUPS + 655 ";"); 656 657 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.GROUP_MEMBERSHIP + ";"); 658 db.execSQL("CREATE VIEW " + LegacyTables.GROUP_MEMBERSHIP + " AS SELECT " + 659 DataColumns.CONCRETE_ID 660 + " AS " + android.provider.Contacts.GroupMembership._ID + ", " + 661 DataColumns.CONCRETE_RAW_CONTACT_ID 662 + " AS " + android.provider.Contacts.GroupMembership.PERSON_ID + ", " + 663 Tables.RAW_CONTACTS + "." + RawContacts.ACCOUNT_NAME 664 + " AS " + RawContacts.ACCOUNT_NAME + ", " + 665 Tables.RAW_CONTACTS + "." + RawContacts.ACCOUNT_TYPE 666 + " AS " + RawContacts.ACCOUNT_TYPE + ", " + 667 GroupMembership.GROUP_ROW_ID 668 + " AS " + android.provider.Contacts.GroupMembership.GROUP_ID + ", " + 669 Groups.TITLE 670 + " AS " + android.provider.Contacts.GroupMembership.NAME + ", " + 671 Groups.NOTES 672 + " AS " + android.provider.Contacts.GroupMembership.NOTES + " , " + 673 Groups.SYSTEM_ID 674 + " AS " + android.provider.Contacts.GroupMembership.SYSTEM_ID + 675 " FROM " + Tables.DATA_JOIN_PACKAGES_MIMETYPES_RAW_CONTACTS_GROUPS + 676 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 677 + GroupMembership.CONTENT_ITEM_TYPE + "'" 678 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" + 679 ";"); 680 681 db.execSQL("DROP VIEW IF EXISTS " + LegacyTables.PHOTOS + ";"); 682 db.execSQL("CREATE VIEW " + LegacyTables.PHOTOS + " AS SELECT " + 683 DataColumns.CONCRETE_ID 684 + " AS " + android.provider.Contacts.Photos._ID + ", " + 685 DataColumns.CONCRETE_RAW_CONTACT_ID 686 + " AS " + android.provider.Contacts.Photos.PERSON_ID + ", " + 687 RawContacts.ACCOUNT_NAME + ", " + 688 RawContacts.ACCOUNT_TYPE + ", " + 689 Tables.DATA + "." + Photo.PHOTO 690 + " AS " + android.provider.Contacts.Photos.DATA + ", " + 691 "legacy_photo." + LegacyPhotoData.EXISTS_ON_SERVER 692 + " AS " + android.provider.Contacts.Photos.EXISTS_ON_SERVER + ", " + 693 "legacy_photo." + LegacyPhotoData.DOWNLOAD_REQUIRED 694 + " AS " + android.provider.Contacts.Photos.DOWNLOAD_REQUIRED + ", " + 695 "legacy_photo." + LegacyPhotoData.LOCAL_VERSION 696 + " AS " + android.provider.Contacts.Photos.LOCAL_VERSION + ", " + 697 "legacy_photo." + LegacyPhotoData.SYNC_ERROR 698 + " AS " + android.provider.Contacts.Photos.SYNC_ERROR + 699 " FROM " + Tables.DATA + DATA_JOINS + LEGACY_PHOTO_JOIN + 700 " WHERE " + MimetypesColumns.CONCRETE_MIMETYPE + "='" 701 + Photo.CONTENT_ITEM_TYPE + "'" 702 + " AND " + Tables.RAW_CONTACTS + "." + RawContacts.DELETED + "=0" 703 + " AND " + RawContacts.IS_RESTRICTED + "=0" + 704 ";"); 705 } 706 707 public Uri insert(Uri uri, ContentValues values) { 708 final int match = sUriMatcher.match(uri); 709 long id = 0; 710 switch (match) { 711 case PEOPLE: 712 id = insertPeople(values); 713 break; 714 715 case ORGANIZATIONS: 716 id = insertOrganization(values); 717 break; 718 719 case PEOPLE_CONTACTMETHODS: { 720 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 721 id = insertContactMethod(rawContactId, values); 722 break; 723 } 724 725 case CONTACTMETHODS: { 726 long rawContactId = getRequiredValue(values, ContactMethods.PERSON_ID); 727 id = insertContactMethod(rawContactId, values); 728 break; 729 } 730 731 case PHONES: { 732 long rawContactId = getRequiredValue(values, 733 android.provider.Contacts.Phones.PERSON_ID); 734 id = insertPhone(rawContactId, values); 735 break; 736 } 737 738 case EXTENSIONS: { 739 long rawContactId = getRequiredValue(values, 740 android.provider.Contacts.Extensions.PERSON_ID); 741 id = insertExtension(rawContactId, values); 742 break; 743 } 744 745 case GROUPS: 746 id = insertGroup(values); 747 break; 748 749 case GROUPMEMBERSHIP: { 750 long rawContactId = getRequiredValue(values, 751 android.provider.Contacts.GroupMembership.PERSON_ID); 752 long groupId = getRequiredValue(values, 753 android.provider.Contacts.GroupMembership.GROUP_ID); 754 id = insertGroupMembership(rawContactId, groupId); 755 break; 756 } 757 758 default: 759 throw new UnsupportedOperationException("Unknown uri: " + uri); 760 } 761 762 if (id < 0) { 763 return null; 764 } 765 766 final Uri result = ContentUris.withAppendedId(uri, id); 767 onChange(result); 768 return result; 769 } 770 771 private long getRequiredValue(ContentValues values, String column) { 772 if (!values.containsKey(column)) { 773 throw new RuntimeException("Required value: " + column); 774 } 775 776 return values.getAsLong(column); 777 } 778 779 private long insertPeople(ContentValues values) { 780 ensureDefaultAccount(); 781 782 mValues.clear(); 783 784 OpenHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 785 values, People.CUSTOM_RINGTONE); 786 OpenHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 787 values, People.SEND_TO_VOICEMAIL); 788 OpenHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 789 values, People.LAST_TIME_CONTACTED); 790 OpenHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 791 values, People.TIMES_CONTACTED); 792 OpenHelper.copyLongValue(mValues, RawContacts.STARRED, 793 values, People.STARRED); 794 mValues.put(RawContacts.ACCOUNT_NAME, mAccount.name); 795 mValues.put(RawContacts.ACCOUNT_TYPE, mAccount.type); 796 Uri contactUri = mContactsProvider.insert(RawContacts.CONTENT_URI, mValues); 797 long rawContactId = ContentUris.parseId(contactUri); 798 799 if (values.containsKey(People.NAME) || values.containsKey(People.PHONETIC_NAME)) { 800 mValues.clear(); 801 mValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId); 802 mValues.put(ContactsContract.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 803 OpenHelper.copyStringValue(mValues, StructuredName.DISPLAY_NAME, 804 values, People.NAME); 805 if (values.containsKey(People.PHONETIC_NAME)) { 806 String phoneticName = values.getAsString(People.PHONETIC_NAME); 807 NameSplitter.Name parsedName = new NameSplitter.Name(); 808 mPhoneticNameSplitter.split(parsedName, phoneticName); 809 mValues.put(StructuredName.PHONETIC_GIVEN_NAME, parsedName.getGivenNames()); 810 mValues.put(StructuredName.PHONETIC_MIDDLE_NAME, parsedName.getMiddleName()); 811 mValues.put(StructuredName.PHONETIC_FAMILY_NAME, parsedName.getFamilyName()); 812 } 813 814 mContactsProvider.insert(ContactsContract.Data.CONTENT_URI, mValues); 815 } 816 817 if (values.containsKey(People.NOTES)) { 818 mValues.clear(); 819 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 820 mValues.put(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE); 821 OpenHelper.copyStringValue(mValues, Note.NOTE, values, People.NOTES); 822 mContactsProvider.insert(Data.CONTENT_URI, mValues); 823 } 824 825 // TODO instant aggregation 826 return rawContactId; 827 } 828 829 private long insertOrganization(ContentValues values) { 830 mValues.clear(); 831 832 OpenHelper.copyLongValue(mValues, Data.RAW_CONTACT_ID, 833 values, android.provider.Contacts.Organizations.PERSON_ID); 834 mValues.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE); 835 836 OpenHelper.copyLongValue(mValues, Data.IS_PRIMARY, 837 values, android.provider.Contacts.Organizations.ISPRIMARY); 838 839 OpenHelper.copyStringValue(mValues, Organization.COMPANY, 840 values, android.provider.Contacts.Organizations.COMPANY); 841 842 // TYPE values happen to remain the same between V1 and V2 - can just copy the value 843 OpenHelper.copyLongValue(mValues, Organization.TYPE, 844 values, android.provider.Contacts.Organizations.TYPE); 845 846 OpenHelper.copyStringValue(mValues, Organization.LABEL, 847 values, android.provider.Contacts.Organizations.LABEL); 848 OpenHelper.copyStringValue(mValues, Organization.TITLE, 849 values, android.provider.Contacts.Organizations.TITLE); 850 851 Uri uri = mContactsProvider.insert(Data.CONTENT_URI, mValues); 852 853 return ContentUris.parseId(uri); 854 } 855 856 private long insertPhone(long rawContactId, ContentValues values) { 857 mValues.clear(); 858 859 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 860 mValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 861 862 OpenHelper.copyLongValue(mValues, Data.IS_PRIMARY, 863 values, android.provider.Contacts.Phones.ISPRIMARY); 864 865 OpenHelper.copyStringValue(mValues, Phone.NUMBER, 866 values, android.provider.Contacts.Phones.NUMBER); 867 868 // TYPE values happen to remain the same between V1 and V2 - can just copy the value 869 OpenHelper.copyLongValue(mValues, Phone.TYPE, 870 values, android.provider.Contacts.Phones.TYPE); 871 872 OpenHelper.copyStringValue(mValues, Phone.LABEL, 873 values, android.provider.Contacts.Phones.LABEL); 874 875 Uri uri = mContactsProvider.insert(Data.CONTENT_URI, mValues); 876 877 return ContentUris.parseId(uri); 878 } 879 880 private long insertContactMethod(long rawContactId, ContentValues values) { 881 Integer kind = values.getAsInteger(ContactMethods.KIND); 882 if (kind == null) { 883 throw new RuntimeException("Required value: " + ContactMethods.KIND); 884 } 885 886 mValues.clear(); 887 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 888 889 OpenHelper.copyLongValue(mValues, Data.IS_PRIMARY, values, ContactMethods.ISPRIMARY); 890 891 switch (kind) { 892 case android.provider.Contacts.KIND_EMAIL: { 893 copyCommonFields(values, Email.CONTENT_ITEM_TYPE, Email.TYPE, Email.LABEL, 894 Data.DATA14); 895 OpenHelper.copyStringValue(mValues, Email.DATA, values, ContactMethods.DATA); 896 break; 897 } 898 899 case android.provider.Contacts.KIND_IM: { 900 String protocol = values.getAsString(ContactMethods.DATA); 901 if (protocol.startsWith("pre:")) { 902 mValues.put(Im.PROTOCOL, Integer.parseInt(protocol.substring(4))); 903 } else if (protocol.startsWith("custom:")) { 904 mValues.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM); 905 mValues.put(Im.CUSTOM_PROTOCOL, protocol.substring(7)); 906 } 907 908 copyCommonFields(values, Im.CONTENT_ITEM_TYPE, Im.TYPE, Im.LABEL, Data.DATA14); 909 break; 910 } 911 912 case android.provider.Contacts.KIND_POSTAL: { 913 copyCommonFields(values, StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, 914 StructuredPostal.LABEL, Data.DATA14); 915 OpenHelper.copyStringValue(mValues, StructuredPostal.FORMATTED_ADDRESS, values, 916 ContactMethods.DATA); 917 break; 918 } 919 } 920 921 Uri uri = mContactsProvider.insert(Data.CONTENT_URI, mValues); 922 return ContentUris.parseId(uri); 923 } 924 925 private void copyCommonFields(ContentValues values, String mimeType, String typeColumn, 926 String labelColumn, String auxDataColumn) { 927 mValues.put(Data.MIMETYPE, mimeType); 928 OpenHelper.copyLongValue(mValues, typeColumn, values, ContactMethods.TYPE); 929 OpenHelper.copyStringValue(mValues, labelColumn, values, ContactMethods.LABEL); 930 OpenHelper.copyStringValue(mValues, auxDataColumn, values, ContactMethods.AUX_DATA); 931 } 932 933 private long insertExtension(long rawContactId, ContentValues values) { 934 mValues.clear(); 935 936 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 937 mValues.put(Data.MIMETYPE, android.provider.Contacts.Extensions.CONTENT_ITEM_TYPE); 938 939 OpenHelper.copyStringValue(mValues, ExtensionsColumns.NAME, 940 values, android.provider.Contacts.People.Extensions.NAME); 941 OpenHelper.copyStringValue(mValues, ExtensionsColumns.VALUE, 942 values, android.provider.Contacts.People.Extensions.VALUE); 943 944 Uri uri = mContactsProvider.insert(Data.CONTENT_URI, mValues); 945 return ContentUris.parseId(uri); 946 } 947 948 private long insertGroup(ContentValues values) { 949 ensureDefaultAccount(); 950 mValues.clear(); 951 952 OpenHelper.copyStringValue(mValues, Groups.TITLE, 953 values, android.provider.Contacts.Groups.NAME); 954 OpenHelper.copyStringValue(mValues, Groups.NOTES, 955 values, android.provider.Contacts.Groups.NOTES); 956 OpenHelper.copyStringValue(mValues, Groups.SYSTEM_ID, 957 values, android.provider.Contacts.Groups.SYSTEM_ID); 958 959 mValues.put(Groups.ACCOUNT_NAME, mAccount.name); 960 mValues.put(Groups.ACCOUNT_TYPE, mAccount.type); 961 962 Uri uri = mContactsProvider.insert(Groups.CONTENT_URI, mValues); 963 return ContentUris.parseId(uri); 964 } 965 966 private long insertGroupMembership(long rawContactId, long groupId) { 967 mValues.clear(); 968 969 mValues.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE); 970 mValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 971 mValues.put(GroupMembership.GROUP_ROW_ID, groupId); 972 973 Uri uri = mContactsProvider.insert(Data.CONTENT_URI, mValues); 974 return ContentUris.parseId(uri); 975 } 976 977 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 978 final int match = sUriMatcher.match(uri); 979 int count = 0; 980 switch(match) { 981 case PEOPLE_UPDATE_CONTACT_TIME: 982 count = updateContactTime(uri, values); 983 break; 984 985 case PEOPLE_PHOTO: { 986 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 987 return updatePhoto(rawContactId, values); 988 } 989 990 case PHOTOS: 991 // TODO 992 break; 993 994 case PHOTOS_ID: 995 // TODO 996 break; 997 998 999 default: 1000 throw new UnsupportedOperationException("Unknown uri: " + uri); 1001 } 1002 1003 if (count > 0) { 1004 mContext.getContentResolver().notifyChange(uri, null); 1005 } 1006 return count; 1007 } 1008 1009 1010 private int updateContactTime(Uri uri, ContentValues values) { 1011 1012 // TODO check sanctions 1013 1014 long lastTimeContacted; 1015 if (values.containsKey(People.LAST_TIME_CONTACTED)) { 1016 lastTimeContacted = values.getAsLong(People.LAST_TIME_CONTACTED); 1017 } else { 1018 lastTimeContacted = System.currentTimeMillis(); 1019 } 1020 1021 long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 1022 long contactId = mOpenHelper.getContactId(rawContactId); 1023 if (contactId != 0) { 1024 mContactsProvider.updateContactTime(contactId, lastTimeContacted); 1025 } else { 1026 mLastTimeContactedUpdate.bindLong(1, lastTimeContacted); 1027 mLastTimeContactedUpdate.bindLong(2, rawContactId); 1028 mLastTimeContactedUpdate.execute(); 1029 } 1030 return 1; 1031 } 1032 1033 private int updatePhoto(long rawContactId, ContentValues values) { 1034 1035 // TODO check sanctions 1036 1037 int count; 1038 1039 long dataId = -1; 1040 Cursor c = mContactsProvider.query(Data.CONTENT_URI, PhotoQuery.COLUMNS, 1041 Data.RAW_CONTACT_ID + "=" + rawContactId + " AND " 1042 + Data.MIMETYPE + "=" + mOpenHelper.getMimeTypeId(Photo.CONTENT_ITEM_TYPE), 1043 null, null); 1044 try { 1045 if (c.moveToFirst()) { 1046 dataId = c.getLong(PhotoQuery._ID); 1047 } 1048 } finally { 1049 c.close(); 1050 } 1051 1052 mValues.clear(); 1053 byte[] bytes = values.getAsByteArray(android.provider.Contacts.Photos.DATA); 1054 mValues.put(Photo.PHOTO, bytes); 1055 1056 if (dataId == -1) { 1057 mValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 1058 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 1059 Uri dataUri = mContactsProvider.insert(Data.CONTENT_URI, mValues); 1060 dataId = ContentUris.parseId(dataUri); 1061 count = 1; 1062 } else { 1063 Uri dataUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId); 1064 count = mContactsProvider.update(dataUri, mValues, null, null); 1065 } 1066 1067 mValues.clear(); 1068 OpenHelper.copyStringValue(mValues, LegacyPhotoData.LOCAL_VERSION, 1069 values, android.provider.Contacts.Photos.LOCAL_VERSION); 1070 OpenHelper.copyStringValue(mValues, LegacyPhotoData.DOWNLOAD_REQUIRED, 1071 values, android.provider.Contacts.Photos.DOWNLOAD_REQUIRED); 1072 OpenHelper.copyStringValue(mValues, LegacyPhotoData.EXISTS_ON_SERVER, 1073 values, android.provider.Contacts.Photos.EXISTS_ON_SERVER); 1074 OpenHelper.copyStringValue(mValues, LegacyPhotoData.SYNC_ERROR, 1075 values, android.provider.Contacts.Photos.SYNC_ERROR); 1076 1077 int updated = mContactsProvider.update(Data.CONTENT_URI, mValues, 1078 Data.MIMETYPE + "='" + LegacyPhotoData.CONTENT_ITEM_TYPE + "'" 1079 + " AND " + Data.RAW_CONTACT_ID + "=" + rawContactId 1080 + " AND " + LegacyPhotoData.PHOTO_DATA_ID + "=" + dataId, null); 1081 if (updated == 0) { 1082 mValues.put(Data.RAW_CONTACT_ID, rawContactId); 1083 mValues.put(Data.MIMETYPE, LegacyPhotoData.CONTENT_ITEM_TYPE); 1084 mValues.put(LegacyPhotoData.PHOTO_DATA_ID, dataId); 1085 mContactsProvider.insert(Data.CONTENT_URI, mValues); 1086 } 1087 1088 return count; 1089 } 1090 1091 public int delete(Uri uri, String selection, String[] selectionArgs) { 1092 final int match = sUriMatcher.match(uri); 1093 int count = 0; 1094 switch (match) { 1095 case PEOPLE_ID: 1096 count = mContactsProvider.deleteRawContact(ContentUris.parseId(uri), false); 1097 break; 1098 1099 case ORGANIZATIONS_ID: 1100 count = mContactsProvider.deleteData(ContentUris.parseId(uri), 1101 ORGANIZATION_MIME_TYPES); 1102 break; 1103 1104 case CONTACTMETHODS_ID: 1105 count = mContactsProvider.deleteData(ContentUris.parseId(uri), 1106 CONTACT_METHOD_MIME_TYPES); 1107 break; 1108 1109 case PHONES_ID: 1110 count = mContactsProvider.deleteData(ContentUris.parseId(uri), 1111 PHONE_MIME_TYPES); 1112 break; 1113 1114 default: 1115 throw new UnsupportedOperationException("Unknown uri: " + uri); 1116 } 1117 1118 return count; 1119 } 1120 1121 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 1122 String sortOrder, String limit) { 1123 ensureDefaultAccount(); 1124 1125 final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 1126 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 1127 String groupBy = null; 1128 1129 final int match = sUriMatcher.match(uri); 1130 switch (match) { 1131 case PEOPLE: { 1132 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1133 qb.setProjectionMap(sPeopleProjectionMap); 1134 applyRawContactsAccount(qb, uri); 1135 break; 1136 } 1137 1138 case PEOPLE_ID: 1139 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1140 qb.setProjectionMap(sPeopleProjectionMap); 1141 applyRawContactsAccount(qb, uri); 1142 qb.appendWhere(" AND " + People._ID + "="); 1143 qb.appendWhere(uri.getPathSegments().get(1)); 1144 break; 1145 1146 case PEOPLE_FILTER: { 1147 qb.setTables(LegacyTables.PEOPLE_JOIN_PRESENCE); 1148 qb.setProjectionMap(sPeopleProjectionMap); 1149 applyRawContactsAccount(qb, uri); 1150 String filterParam = uri.getPathSegments().get(2); 1151 qb.appendWhere(" AND " + People._ID + " IN " 1152 + mContactsProvider.getRawContactsByFilterAsNestedQuery(filterParam)); 1153 break; 1154 } 1155 1156 case ORGANIZATIONS: 1157 qb.setTables(LegacyTables.ORGANIZATIONS + " organizations"); 1158 qb.setProjectionMap(sOrganizationProjectionMap); 1159 applyRawContactsAccount(qb, uri); 1160 break; 1161 1162 case ORGANIZATIONS_ID: 1163 qb.setTables(LegacyTables.ORGANIZATIONS + " organizations"); 1164 qb.setProjectionMap(sOrganizationProjectionMap); 1165 applyRawContactsAccount(qb, uri); 1166 qb.appendWhere(" AND " + android.provider.Contacts.Organizations._ID + "="); 1167 qb.appendWhere(uri.getPathSegments().get(1)); 1168 break; 1169 1170 case CONTACTMETHODS: 1171 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1172 qb.setProjectionMap(sContactMethodProjectionMap); 1173 applyRawContactsAccount(qb, uri); 1174 break; 1175 1176 case CONTACTMETHODS_ID: 1177 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1178 qb.setProjectionMap(sContactMethodProjectionMap); 1179 applyRawContactsAccount(qb, uri); 1180 qb.appendWhere(" AND " + ContactMethods._ID + "="); 1181 qb.appendWhere(uri.getPathSegments().get(1)); 1182 break; 1183 1184 case PEOPLE_CONTACTMETHODS: 1185 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1186 qb.setProjectionMap(sContactMethodProjectionMap); 1187 applyRawContactsAccount(qb, uri); 1188 qb.appendWhere(" AND " + ContactMethods.PERSON_ID + "="); 1189 qb.appendWhere(uri.getPathSegments().get(1)); 1190 qb.appendWhere(" AND " + ContactMethods.KIND + " IS NOT NULL"); 1191 break; 1192 1193 case PEOPLE_CONTACTMETHODS_ID: 1194 qb.setTables(LegacyTables.CONTACT_METHODS + " contact_methods"); 1195 qb.setProjectionMap(sContactMethodProjectionMap); 1196 applyRawContactsAccount(qb, uri); 1197 qb.appendWhere(" AND " + ContactMethods.PERSON_ID + "="); 1198 qb.appendWhere(uri.getPathSegments().get(1)); 1199 qb.appendWhere(" AND " + ContactMethods._ID + "="); 1200 qb.appendWhere(uri.getPathSegments().get(3)); 1201 qb.appendWhere(" AND " + ContactMethods.KIND + " IS NOT NULL"); 1202 break; 1203 1204 case PHONES: 1205 qb.setTables(LegacyTables.PHONES + " phones"); 1206 qb.setProjectionMap(sPhoneProjectionMap); 1207 applyRawContactsAccount(qb, uri); 1208 break; 1209 1210 case PHONES_ID: 1211 qb.setTables(LegacyTables.PHONES + " phones"); 1212 qb.setProjectionMap(sPhoneProjectionMap); 1213 applyRawContactsAccount(qb, uri); 1214 qb.appendWhere(" AND " + android.provider.Contacts.Phones._ID + "="); 1215 qb.appendWhere(uri.getPathSegments().get(1)); 1216 break; 1217 1218 case PHONES_FILTER: 1219 qb.setTables(LegacyTables.PHONES + " phones"); 1220 qb.setProjectionMap(sPhoneProjectionMap); 1221 applyRawContactsAccount(qb, uri); 1222 if (uri.getPathSegments().size() > 2) { 1223 String filterParam = uri.getLastPathSegment(); 1224 qb.appendWhere(" AND person ="); 1225 qb.appendWhere(mOpenHelper.buildPhoneLookupAsNestedQuery(filterParam)); 1226 } 1227 break; 1228 1229 case PEOPLE_PHONES: 1230 qb.setTables(LegacyTables.PHONES + " phones"); 1231 qb.setProjectionMap(sPhoneProjectionMap); 1232 applyRawContactsAccount(qb, uri); 1233 qb.appendWhere(" AND " + android.provider.Contacts.Phones.PERSON_ID + "="); 1234 qb.appendWhere(uri.getPathSegments().get(1)); 1235 break; 1236 1237 case PEOPLE_PHONES_ID: 1238 qb.setTables(LegacyTables.PHONES + " phones"); 1239 qb.setProjectionMap(sPhoneProjectionMap); 1240 applyRawContactsAccount(qb, uri); 1241 qb.appendWhere(" AND " + android.provider.Contacts.Phones.PERSON_ID + "="); 1242 qb.appendWhere(uri.getPathSegments().get(1)); 1243 qb.appendWhere(" AND " + android.provider.Contacts.Phones._ID + "="); 1244 qb.appendWhere(uri.getPathSegments().get(3)); 1245 break; 1246 1247 case EXTENSIONS: 1248 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1249 qb.setProjectionMap(sExtensionProjectionMap); 1250 applyRawContactsAccount(qb, uri); 1251 break; 1252 1253 case EXTENSIONS_ID: 1254 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1255 qb.setProjectionMap(sExtensionProjectionMap); 1256 applyRawContactsAccount(qb, uri); 1257 qb.appendWhere(" AND " + android.provider.Contacts.Extensions._ID + "="); 1258 qb.appendWhere(uri.getPathSegments().get(1)); 1259 break; 1260 1261 case PEOPLE_EXTENSIONS: 1262 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1263 qb.setProjectionMap(sExtensionProjectionMap); 1264 applyRawContactsAccount(qb, uri); 1265 qb.appendWhere(" AND " + android.provider.Contacts.Extensions.PERSON_ID + "="); 1266 qb.appendWhere(uri.getPathSegments().get(1)); 1267 break; 1268 1269 case PEOPLE_EXTENSIONS_ID: 1270 qb.setTables(LegacyTables.EXTENSIONS + " extensions"); 1271 qb.setProjectionMap(sExtensionProjectionMap); 1272 applyRawContactsAccount(qb, uri); 1273 qb.appendWhere(" AND " + android.provider.Contacts.Extensions.PERSON_ID + "="); 1274 qb.appendWhere(uri.getPathSegments().get(1)); 1275 qb.appendWhere(" AND " + android.provider.Contacts.Extensions._ID + "="); 1276 qb.appendWhere(uri.getPathSegments().get(3)); 1277 break; 1278 1279 case GROUPS: 1280 qb.setTables(LegacyTables.GROUPS + " groups"); 1281 qb.setProjectionMap(sGroupProjectionMap); 1282 applyGroupAccount(qb, uri); 1283 break; 1284 1285 case GROUPS_ID: 1286 qb.setTables(LegacyTables.GROUPS + " groups"); 1287 qb.setProjectionMap(sGroupProjectionMap); 1288 applyGroupAccount(qb, uri); 1289 qb.appendWhere(" AND " + android.provider.Contacts.Groups._ID + "="); 1290 qb.appendWhere(uri.getPathSegments().get(1)); 1291 break; 1292 1293 case GROUPMEMBERSHIP: 1294 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1295 qb.setProjectionMap(sGroupMembershipProjectionMap); 1296 applyRawContactsAccount(qb, uri); 1297 break; 1298 1299 case GROUPMEMBERSHIP_ID: 1300 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1301 qb.setProjectionMap(sGroupMembershipProjectionMap); 1302 applyRawContactsAccount(qb, uri); 1303 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership._ID + "="); 1304 qb.appendWhere(uri.getPathSegments().get(1)); 1305 break; 1306 1307 case PEOPLE_GROUPMEMBERSHIP: 1308 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1309 qb.setProjectionMap(sGroupMembershipProjectionMap); 1310 applyRawContactsAccount(qb, uri); 1311 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership.PERSON_ID + "="); 1312 qb.appendWhere(uri.getPathSegments().get(1)); 1313 break; 1314 1315 case PEOPLE_GROUPMEMBERSHIP_ID: 1316 qb.setTables(LegacyTables.GROUP_MEMBERSHIP + " groupmembership"); 1317 qb.setProjectionMap(sGroupMembershipProjectionMap); 1318 applyRawContactsAccount(qb, uri); 1319 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership.PERSON_ID + "="); 1320 qb.appendWhere(uri.getPathSegments().get(1)); 1321 qb.appendWhere(" AND " + android.provider.Contacts.GroupMembership._ID + "="); 1322 qb.appendWhere(uri.getPathSegments().get(3)); 1323 break; 1324 1325 case PEOPLE_PHOTO: 1326 qb.setTables(LegacyTables.PHOTOS + " photos"); 1327 qb.setProjectionMap(sPhotoProjectionMap); 1328 applyRawContactsAccount(qb, uri); 1329 qb.appendWhere(" AND " + android.provider.Contacts.Photos.PERSON_ID + "="); 1330 qb.appendWhere(uri.getPathSegments().get(1)); 1331 limit = "1"; 1332 break; 1333 1334 case SEARCH_SUGGESTIONS: 1335 1336 // No legacy compatibility for search suggestions 1337 return mGlobalSearchSupport.handleSearchSuggestionsQuery(db, uri, limit); 1338 1339 case SEARCH_SHORTCUT: { 1340 long contactId = ContentUris.parseId(uri); 1341 return mGlobalSearchSupport.handleSearchShortcutRefresh(db, contactId, projection); 1342 } 1343 1344 case DELETED_PEOPLE: 1345 case DELETED_GROUPS: 1346 throw new UnsupportedOperationException(); 1347 1348 default: 1349 throw new IllegalArgumentException("Unknown URL " + uri); 1350 } 1351 1352 // Perform the query and set the notification uri 1353 final Cursor c = qb.query(db, projection, selection, selectionArgs, 1354 groupBy, null, sortOrder, limit); 1355 if (c != null) { 1356 c.setNotificationUri(mContext.getContentResolver(), RawContacts.CONTENT_URI); 1357 } 1358 return c; 1359 } 1360 1361 private void applyRawContactsAccount(SQLiteQueryBuilder qb, Uri uri) { 1362 StringBuilder sb = new StringBuilder(); 1363 sb.append(RawContacts.ACCOUNT_NAME + "="); 1364 DatabaseUtils.appendEscapedSQLString(sb, mAccount.name); 1365 sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 1366 DatabaseUtils.appendEscapedSQLString(sb, mAccount.type); 1367 qb.appendWhere(sb.toString()); 1368 } 1369 1370 private void applyGroupAccount(SQLiteQueryBuilder qb, Uri uri) { 1371 StringBuilder sb = new StringBuilder(); 1372 sb.append(Groups.ACCOUNT_NAME + "="); 1373 DatabaseUtils.appendEscapedSQLString(sb, mAccount.name); 1374 sb.append(" AND " + Groups.ACCOUNT_TYPE + "="); 1375 DatabaseUtils.appendEscapedSQLString(sb, mAccount.type); 1376 qb.appendWhere(sb.toString()); 1377 } 1378 1379 /** 1380 * Called when a change has been made. 1381 * 1382 * @param uri the uri that the change was made to 1383 */ 1384 private void onChange(Uri uri) { 1385 mContext.getContentResolver().notifyChange(android.provider.Contacts.CONTENT_URI, null); 1386 } 1387 1388 public String getType(Uri uri) { 1389 int match = sUriMatcher.match(uri); 1390 switch (match) { 1391 case EXTENSIONS: 1392 case PEOPLE_EXTENSIONS: 1393 return Extensions.CONTENT_TYPE; 1394 case EXTENSIONS_ID: 1395 case PEOPLE_EXTENSIONS_ID: 1396 return Extensions.CONTENT_ITEM_TYPE; 1397 case PEOPLE: 1398 return "vnd.android.cursor.dir/person"; 1399 case PEOPLE_ID: 1400 return "vnd.android.cursor.item/person"; 1401 case PEOPLE_PHONES: 1402 return "vnd.android.cursor.dir/phone"; 1403 case PEOPLE_PHONES_ID: 1404 return "vnd.android.cursor.item/phone"; 1405 case PEOPLE_CONTACTMETHODS: 1406 return "vnd.android.cursor.dir/contact-methods"; 1407 case PEOPLE_CONTACTMETHODS_ID: 1408 return getContactMethodType(uri); 1409 case PHONES: 1410 return "vnd.android.cursor.dir/phone"; 1411 case PHONES_ID: 1412 return "vnd.android.cursor.item/phone"; 1413 case PHONES_FILTER: 1414 return "vnd.android.cursor.dir/phone"; 1415 case PHOTOS_ID: 1416 return "vnd.android.cursor.item/photo"; 1417 case PHOTOS: 1418 return "vnd.android.cursor.dir/photo"; 1419 case PEOPLE_PHOTO: 1420 return "vnd.android.cursor.item/photo"; 1421 case CONTACTMETHODS: 1422 return "vnd.android.cursor.dir/contact-methods"; 1423 case CONTACTMETHODS_ID: 1424 return getContactMethodType(uri); 1425 case ORGANIZATIONS: 1426 return "vnd.android.cursor.dir/organizations"; 1427 case ORGANIZATIONS_ID: 1428 return "vnd.android.cursor.item/organization"; 1429 case SEARCH_SUGGESTIONS: 1430 return SearchManager.SUGGEST_MIME_TYPE; 1431 case SEARCH_SHORTCUT: 1432 return SearchManager.SHORTCUT_MIME_TYPE; 1433 default: 1434 throw new IllegalArgumentException("Unknown URI"); 1435 } 1436 } 1437 1438 private String getContactMethodType(Uri url) { 1439 String mime = null; 1440 1441 Cursor c = query(url, new String[] {ContactMethods.KIND}, null, null, null, null); 1442 if (c != null) { 1443 try { 1444 if (c.moveToFirst()) { 1445 int kind = c.getInt(0); 1446 switch (kind) { 1447 case Contacts.KIND_EMAIL: 1448 mime = "vnd.android.cursor.item/email"; 1449 break; 1450 1451 case Contacts.KIND_IM: 1452 mime = "vnd.android.cursor.item/jabber-im"; 1453 break; 1454 1455 case Contacts.KIND_POSTAL: 1456 mime = "vnd.android.cursor.item/postal-address"; 1457 break; 1458 } 1459 } 1460 } finally { 1461 c.close(); 1462 } 1463 } 1464 return mime; 1465 } 1466} 1467