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