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