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