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