ContactsProvider2Test.java revision 36612112760df799ef89f7e324e5dfabd5ca0d2b
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 */ 16 17package com.android.providers.contacts; 18 19import com.android.internal.util.ArrayUtils; 20import com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; 21import com.android.providers.contacts.ContactsDatabaseHelper.DataUsageStatColumns; 22import com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 23import com.android.providers.contacts.tests.R; 24import com.google.android.collect.Lists; 25 26import android.accounts.Account; 27import android.content.ContentProviderOperation; 28import android.content.ContentProviderResult; 29import android.content.ContentUris; 30import android.content.ContentValues; 31import android.content.Entity; 32import android.content.EntityIterator; 33import android.content.res.AssetFileDescriptor; 34import android.database.Cursor; 35import android.database.sqlite.SQLiteConstraintException; 36import android.net.Uri; 37import android.os.AsyncTask; 38import android.provider.ContactsContract; 39import android.provider.ContactsContract.AggregationExceptions; 40import android.provider.ContactsContract.CommonDataKinds.Email; 41import android.provider.ContactsContract.CommonDataKinds.GroupMembership; 42import android.provider.ContactsContract.CommonDataKinds.Im; 43import android.provider.ContactsContract.CommonDataKinds.Organization; 44import android.provider.ContactsContract.CommonDataKinds.Phone; 45import android.provider.ContactsContract.CommonDataKinds.Photo; 46import android.provider.ContactsContract.CommonDataKinds.StructuredName; 47import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 48import android.provider.ContactsContract.ContactCounts; 49import android.provider.ContactsContract.Contacts; 50import android.provider.ContactsContract.Data; 51import android.provider.ContactsContract.DataUsageFeedback; 52import android.provider.ContactsContract.Directory; 53import android.provider.ContactsContract.DisplayNameSources; 54import android.provider.ContactsContract.DisplayPhoto; 55import android.provider.ContactsContract.FullNameStyle; 56import android.provider.ContactsContract.Groups; 57import android.provider.ContactsContract.PhoneLookup; 58import android.provider.ContactsContract.PhoneticNameStyle; 59import android.provider.ContactsContract.Profile; 60import android.provider.ContactsContract.ProviderStatus; 61import android.provider.ContactsContract.RawContacts; 62import android.provider.ContactsContract.RawContactsEntity; 63import android.provider.ContactsContract.SearchSnippetColumns; 64import android.provider.ContactsContract.Settings; 65import android.provider.ContactsContract.StatusUpdates; 66import android.provider.ContactsContract.StreamItemPhotos; 67import android.provider.ContactsContract.StreamItems; 68import android.provider.LiveFolders; 69import android.provider.OpenableColumns; 70import android.test.MoreAsserts; 71import android.test.suitebuilder.annotation.LargeTest; 72import android.text.TextUtils; 73 74import java.io.FileInputStream; 75import java.io.IOException; 76import java.io.InputStream; 77import java.io.OutputStream; 78import java.text.Collator; 79import java.util.ArrayList; 80import java.util.Arrays; 81import java.util.List; 82import java.util.Locale; 83 84/** 85 * Unit tests for {@link ContactsProvider2}. 86 * 87 * Run the test like this: 88 * <code> 89 * adb shell am instrument -e class com.android.providers.contacts.ContactsProvider2Test -w \ 90 * com.android.providers.contacts.tests/android.test.InstrumentationTestRunner 91 * </code> 92 */ 93@LargeTest 94public class ContactsProvider2Test extends BaseContactsProvider2Test { 95 96 private static final Account ACCOUNT_1 = new Account("account_name_1", "account_type_1"); 97 private static final Account ACCOUNT_2 = new Account("account_name_2", "account_type_2"); 98 99 public void testContactsProjection() { 100 assertProjection(Contacts.CONTENT_URI, new String[]{ 101 Contacts._ID, 102 Contacts.DISPLAY_NAME_PRIMARY, 103 Contacts.DISPLAY_NAME_ALTERNATIVE, 104 Contacts.DISPLAY_NAME_SOURCE, 105 Contacts.PHONETIC_NAME, 106 Contacts.PHONETIC_NAME_STYLE, 107 Contacts.SORT_KEY_PRIMARY, 108 Contacts.SORT_KEY_ALTERNATIVE, 109 Contacts.LAST_TIME_CONTACTED, 110 Contacts.TIMES_CONTACTED, 111 Contacts.STARRED, 112 Contacts.IN_VISIBLE_GROUP, 113 Contacts.PHOTO_ID, 114 Contacts.PHOTO_FILE_ID, 115 Contacts.PHOTO_URI, 116 Contacts.PHOTO_THUMBNAIL_URI, 117 Contacts.CUSTOM_RINGTONE, 118 Contacts.HAS_PHONE_NUMBER, 119 Contacts.SEND_TO_VOICEMAIL, 120 Contacts.IS_USER_PROFILE, 121 Contacts.LOOKUP_KEY, 122 Contacts.NAME_RAW_CONTACT_ID, 123 Contacts.CONTACT_PRESENCE, 124 Contacts.CONTACT_CHAT_CAPABILITY, 125 Contacts.CONTACT_STATUS, 126 Contacts.CONTACT_STATUS_TIMESTAMP, 127 Contacts.CONTACT_STATUS_RES_PACKAGE, 128 Contacts.CONTACT_STATUS_LABEL, 129 Contacts.CONTACT_STATUS_ICON, 130 }); 131 } 132 133 public void testContactsWithSnippetProjection() { 134 assertProjection(Contacts.CONTENT_FILTER_URI.buildUpon().appendPath("nothing").build(), 135 new String[]{ 136 Contacts._ID, 137 Contacts.DISPLAY_NAME_PRIMARY, 138 Contacts.DISPLAY_NAME_ALTERNATIVE, 139 Contacts.DISPLAY_NAME_SOURCE, 140 Contacts.PHONETIC_NAME, 141 Contacts.PHONETIC_NAME_STYLE, 142 Contacts.SORT_KEY_PRIMARY, 143 Contacts.SORT_KEY_ALTERNATIVE, 144 Contacts.LAST_TIME_CONTACTED, 145 Contacts.TIMES_CONTACTED, 146 Contacts.STARRED, 147 Contacts.IN_VISIBLE_GROUP, 148 Contacts.PHOTO_ID, 149 Contacts.PHOTO_FILE_ID, 150 Contacts.PHOTO_URI, 151 Contacts.PHOTO_THUMBNAIL_URI, 152 Contacts.CUSTOM_RINGTONE, 153 Contacts.HAS_PHONE_NUMBER, 154 Contacts.SEND_TO_VOICEMAIL, 155 Contacts.IS_USER_PROFILE, 156 Contacts.LOOKUP_KEY, 157 Contacts.NAME_RAW_CONTACT_ID, 158 Contacts.CONTACT_PRESENCE, 159 Contacts.CONTACT_CHAT_CAPABILITY, 160 Contacts.CONTACT_STATUS, 161 Contacts.CONTACT_STATUS_TIMESTAMP, 162 Contacts.CONTACT_STATUS_RES_PACKAGE, 163 Contacts.CONTACT_STATUS_LABEL, 164 Contacts.CONTACT_STATUS_ICON, 165 166 SearchSnippetColumns.SNIPPET, 167 }); 168 } 169 170 public void testRawContactsProjection() { 171 assertProjection(RawContacts.CONTENT_URI, new String[]{ 172 RawContacts._ID, 173 RawContacts.CONTACT_ID, 174 RawContacts.ACCOUNT_NAME, 175 RawContacts.ACCOUNT_TYPE, 176 RawContacts.DATA_SET, 177 RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 178 RawContacts.SOURCE_ID, 179 RawContacts.VERSION, 180 RawContacts.RAW_CONTACT_IS_USER_PROFILE, 181 RawContacts.DIRTY, 182 RawContacts.DELETED, 183 RawContacts.DISPLAY_NAME_PRIMARY, 184 RawContacts.DISPLAY_NAME_ALTERNATIVE, 185 RawContacts.DISPLAY_NAME_SOURCE, 186 RawContacts.PHONETIC_NAME, 187 RawContacts.PHONETIC_NAME_STYLE, 188 RawContacts.NAME_VERIFIED, 189 RawContacts.SORT_KEY_PRIMARY, 190 RawContacts.SORT_KEY_ALTERNATIVE, 191 RawContacts.TIMES_CONTACTED, 192 RawContacts.LAST_TIME_CONTACTED, 193 RawContacts.CUSTOM_RINGTONE, 194 RawContacts.SEND_TO_VOICEMAIL, 195 RawContacts.STARRED, 196 RawContacts.AGGREGATION_MODE, 197 RawContacts.SYNC1, 198 RawContacts.SYNC2, 199 RawContacts.SYNC3, 200 RawContacts.SYNC4, 201 }); 202 } 203 204 public void testDataProjection() { 205 assertProjection(Data.CONTENT_URI, new String[]{ 206 Data._ID, 207 Data.RAW_CONTACT_ID, 208 Data.DATA_VERSION, 209 Data.IS_PRIMARY, 210 Data.IS_SUPER_PRIMARY, 211 Data.RES_PACKAGE, 212 Data.MIMETYPE, 213 Data.DATA1, 214 Data.DATA2, 215 Data.DATA3, 216 Data.DATA4, 217 Data.DATA5, 218 Data.DATA6, 219 Data.DATA7, 220 Data.DATA8, 221 Data.DATA9, 222 Data.DATA10, 223 Data.DATA11, 224 Data.DATA12, 225 Data.DATA13, 226 Data.DATA14, 227 Data.DATA15, 228 Data.SYNC1, 229 Data.SYNC2, 230 Data.SYNC3, 231 Data.SYNC4, 232 Data.CONTACT_ID, 233 Data.PRESENCE, 234 Data.CHAT_CAPABILITY, 235 Data.STATUS, 236 Data.STATUS_TIMESTAMP, 237 Data.STATUS_RES_PACKAGE, 238 Data.STATUS_LABEL, 239 Data.STATUS_ICON, 240 RawContacts.ACCOUNT_NAME, 241 RawContacts.ACCOUNT_TYPE, 242 RawContacts.DATA_SET, 243 RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 244 RawContacts.SOURCE_ID, 245 RawContacts.VERSION, 246 RawContacts.DIRTY, 247 RawContacts.NAME_VERIFIED, 248 RawContacts.RAW_CONTACT_IS_USER_PROFILE, 249 Contacts._ID, 250 Contacts.DISPLAY_NAME_PRIMARY, 251 Contacts.DISPLAY_NAME_ALTERNATIVE, 252 Contacts.DISPLAY_NAME_SOURCE, 253 Contacts.PHONETIC_NAME, 254 Contacts.PHONETIC_NAME_STYLE, 255 Contacts.SORT_KEY_PRIMARY, 256 Contacts.SORT_KEY_ALTERNATIVE, 257 Contacts.LAST_TIME_CONTACTED, 258 Contacts.TIMES_CONTACTED, 259 Contacts.STARRED, 260 Contacts.IN_VISIBLE_GROUP, 261 Contacts.PHOTO_ID, 262 Contacts.PHOTO_FILE_ID, 263 Contacts.PHOTO_URI, 264 Contacts.PHOTO_THUMBNAIL_URI, 265 Contacts.CUSTOM_RINGTONE, 266 Contacts.SEND_TO_VOICEMAIL, 267 Contacts.LOOKUP_KEY, 268 Contacts.NAME_RAW_CONTACT_ID, 269 Contacts.HAS_PHONE_NUMBER, 270 Contacts.CONTACT_PRESENCE, 271 Contacts.CONTACT_CHAT_CAPABILITY, 272 Contacts.CONTACT_STATUS, 273 Contacts.CONTACT_STATUS_TIMESTAMP, 274 Contacts.CONTACT_STATUS_RES_PACKAGE, 275 Contacts.CONTACT_STATUS_LABEL, 276 Contacts.CONTACT_STATUS_ICON, 277 GroupMembership.GROUP_SOURCE_ID, 278 }); 279 } 280 281 public void testDistinctDataProjection() { 282 assertProjection(Phone.CONTENT_FILTER_URI.buildUpon().appendPath("123").build(), 283 new String[]{ 284 Data._ID, 285 Data.DATA_VERSION, 286 Data.IS_PRIMARY, 287 Data.IS_SUPER_PRIMARY, 288 Data.RES_PACKAGE, 289 Data.MIMETYPE, 290 Data.DATA1, 291 Data.DATA2, 292 Data.DATA3, 293 Data.DATA4, 294 Data.DATA5, 295 Data.DATA6, 296 Data.DATA7, 297 Data.DATA8, 298 Data.DATA9, 299 Data.DATA10, 300 Data.DATA11, 301 Data.DATA12, 302 Data.DATA13, 303 Data.DATA14, 304 Data.DATA15, 305 Data.SYNC1, 306 Data.SYNC2, 307 Data.SYNC3, 308 Data.SYNC4, 309 Data.CONTACT_ID, 310 Data.PRESENCE, 311 Data.CHAT_CAPABILITY, 312 Data.STATUS, 313 Data.STATUS_TIMESTAMP, 314 Data.STATUS_RES_PACKAGE, 315 Data.STATUS_LABEL, 316 Data.STATUS_ICON, 317 RawContacts.RAW_CONTACT_IS_USER_PROFILE, 318 Contacts._ID, 319 Contacts.DISPLAY_NAME_PRIMARY, 320 Contacts.DISPLAY_NAME_ALTERNATIVE, 321 Contacts.DISPLAY_NAME_SOURCE, 322 Contacts.PHONETIC_NAME, 323 Contacts.PHONETIC_NAME_STYLE, 324 Contacts.SORT_KEY_PRIMARY, 325 Contacts.SORT_KEY_ALTERNATIVE, 326 Contacts.LAST_TIME_CONTACTED, 327 Contacts.TIMES_CONTACTED, 328 Contacts.STARRED, 329 Contacts.IN_VISIBLE_GROUP, 330 Contacts.PHOTO_ID, 331 Contacts.PHOTO_FILE_ID, 332 Contacts.PHOTO_URI, 333 Contacts.PHOTO_THUMBNAIL_URI, 334 Contacts.HAS_PHONE_NUMBER, 335 Contacts.CUSTOM_RINGTONE, 336 Contacts.SEND_TO_VOICEMAIL, 337 Contacts.LOOKUP_KEY, 338 Contacts.CONTACT_PRESENCE, 339 Contacts.CONTACT_CHAT_CAPABILITY, 340 Contacts.CONTACT_STATUS, 341 Contacts.CONTACT_STATUS_TIMESTAMP, 342 Contacts.CONTACT_STATUS_RES_PACKAGE, 343 Contacts.CONTACT_STATUS_LABEL, 344 Contacts.CONTACT_STATUS_ICON, 345 GroupMembership.GROUP_SOURCE_ID, 346 }); 347 } 348 349 public void testEntityProjection() { 350 assertProjection( 351 Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, 0), 352 Contacts.Entity.CONTENT_DIRECTORY), 353 new String[]{ 354 Contacts.Entity._ID, 355 Contacts.Entity.DATA_ID, 356 Contacts.Entity.RAW_CONTACT_ID, 357 Data.DATA_VERSION, 358 Data.IS_PRIMARY, 359 Data.IS_SUPER_PRIMARY, 360 Data.RES_PACKAGE, 361 Data.MIMETYPE, 362 Data.DATA1, 363 Data.DATA2, 364 Data.DATA3, 365 Data.DATA4, 366 Data.DATA5, 367 Data.DATA6, 368 Data.DATA7, 369 Data.DATA8, 370 Data.DATA9, 371 Data.DATA10, 372 Data.DATA11, 373 Data.DATA12, 374 Data.DATA13, 375 Data.DATA14, 376 Data.DATA15, 377 Data.SYNC1, 378 Data.SYNC2, 379 Data.SYNC3, 380 Data.SYNC4, 381 Data.CONTACT_ID, 382 Data.PRESENCE, 383 Data.CHAT_CAPABILITY, 384 Data.STATUS, 385 Data.STATUS_TIMESTAMP, 386 Data.STATUS_RES_PACKAGE, 387 Data.STATUS_LABEL, 388 Data.STATUS_ICON, 389 RawContacts.ACCOUNT_NAME, 390 RawContacts.ACCOUNT_TYPE, 391 RawContacts.DATA_SET, 392 RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 393 RawContacts.SOURCE_ID, 394 RawContacts.VERSION, 395 RawContacts.DELETED, 396 RawContacts.DIRTY, 397 RawContacts.NAME_VERIFIED, 398 RawContacts.SYNC1, 399 RawContacts.SYNC2, 400 RawContacts.SYNC3, 401 RawContacts.SYNC4, 402 Contacts._ID, 403 Contacts.DISPLAY_NAME_PRIMARY, 404 Contacts.DISPLAY_NAME_ALTERNATIVE, 405 Contacts.DISPLAY_NAME_SOURCE, 406 Contacts.PHONETIC_NAME, 407 Contacts.PHONETIC_NAME_STYLE, 408 Contacts.SORT_KEY_PRIMARY, 409 Contacts.SORT_KEY_ALTERNATIVE, 410 Contacts.LAST_TIME_CONTACTED, 411 Contacts.TIMES_CONTACTED, 412 Contacts.STARRED, 413 Contacts.IN_VISIBLE_GROUP, 414 Contacts.PHOTO_ID, 415 Contacts.PHOTO_FILE_ID, 416 Contacts.PHOTO_URI, 417 Contacts.PHOTO_THUMBNAIL_URI, 418 Contacts.CUSTOM_RINGTONE, 419 Contacts.SEND_TO_VOICEMAIL, 420 Contacts.IS_USER_PROFILE, 421 Contacts.LOOKUP_KEY, 422 Contacts.NAME_RAW_CONTACT_ID, 423 Contacts.HAS_PHONE_NUMBER, 424 Contacts.CONTACT_PRESENCE, 425 Contacts.CONTACT_CHAT_CAPABILITY, 426 Contacts.CONTACT_STATUS, 427 Contacts.CONTACT_STATUS_TIMESTAMP, 428 Contacts.CONTACT_STATUS_RES_PACKAGE, 429 Contacts.CONTACT_STATUS_LABEL, 430 Contacts.CONTACT_STATUS_ICON, 431 GroupMembership.GROUP_SOURCE_ID, 432 }); 433 } 434 435 public void testRawEntityProjection() { 436 assertProjection(RawContactsEntity.CONTENT_URI, new String[]{ 437 RawContacts.Entity.DATA_ID, 438 RawContacts._ID, 439 RawContacts.CONTACT_ID, 440 RawContacts.ACCOUNT_NAME, 441 RawContacts.ACCOUNT_TYPE, 442 RawContacts.DATA_SET, 443 RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 444 RawContacts.SOURCE_ID, 445 RawContacts.VERSION, 446 RawContacts.DIRTY, 447 RawContacts.NAME_VERIFIED, 448 RawContacts.DELETED, 449 RawContacts.SYNC1, 450 RawContacts.SYNC2, 451 RawContacts.SYNC3, 452 RawContacts.SYNC4, 453 RawContacts.STARRED, 454 RawContacts.RAW_CONTACT_IS_USER_PROFILE, 455 Data.DATA_VERSION, 456 Data.IS_PRIMARY, 457 Data.IS_SUPER_PRIMARY, 458 Data.RES_PACKAGE, 459 Data.MIMETYPE, 460 Data.DATA1, 461 Data.DATA2, 462 Data.DATA3, 463 Data.DATA4, 464 Data.DATA5, 465 Data.DATA6, 466 Data.DATA7, 467 Data.DATA8, 468 Data.DATA9, 469 Data.DATA10, 470 Data.DATA11, 471 Data.DATA12, 472 Data.DATA13, 473 Data.DATA14, 474 Data.DATA15, 475 Data.SYNC1, 476 Data.SYNC2, 477 Data.SYNC3, 478 Data.SYNC4, 479 GroupMembership.GROUP_SOURCE_ID, 480 }); 481 } 482 483 public void testPhoneLookupProjection() { 484 assertProjection(PhoneLookup.CONTENT_FILTER_URI.buildUpon().appendPath("123").build(), 485 new String[]{ 486 PhoneLookup._ID, 487 PhoneLookup.LOOKUP_KEY, 488 PhoneLookup.DISPLAY_NAME, 489 PhoneLookup.LAST_TIME_CONTACTED, 490 PhoneLookup.TIMES_CONTACTED, 491 PhoneLookup.STARRED, 492 PhoneLookup.IN_VISIBLE_GROUP, 493 PhoneLookup.PHOTO_ID, 494 PhoneLookup.PHOTO_URI, 495 PhoneLookup.PHOTO_THUMBNAIL_URI, 496 PhoneLookup.CUSTOM_RINGTONE, 497 PhoneLookup.HAS_PHONE_NUMBER, 498 PhoneLookup.SEND_TO_VOICEMAIL, 499 PhoneLookup.NUMBER, 500 PhoneLookup.TYPE, 501 PhoneLookup.LABEL, 502 PhoneLookup.NORMALIZED_NUMBER, 503 }); 504 } 505 506 public void testGroupsProjection() { 507 assertProjection(Groups.CONTENT_URI, new String[]{ 508 Groups._ID, 509 Groups.ACCOUNT_NAME, 510 Groups.ACCOUNT_TYPE, 511 Groups.DATA_SET, 512 Groups.ACCOUNT_TYPE_AND_DATA_SET, 513 Groups.SOURCE_ID, 514 Groups.DIRTY, 515 Groups.VERSION, 516 Groups.RES_PACKAGE, 517 Groups.TITLE, 518 Groups.TITLE_RES, 519 Groups.GROUP_VISIBLE, 520 Groups.SYSTEM_ID, 521 Groups.DELETED, 522 Groups.NOTES, 523 Groups.SHOULD_SYNC, 524 Groups.FAVORITES, 525 Groups.AUTO_ADD, 526 Groups.GROUP_IS_READ_ONLY, 527 Groups.SYNC1, 528 Groups.SYNC2, 529 Groups.SYNC3, 530 Groups.SYNC4, 531 }); 532 } 533 534 public void testGroupsSummaryProjection() { 535 assertProjection(Groups.CONTENT_SUMMARY_URI, new String[]{ 536 Groups._ID, 537 Groups.ACCOUNT_NAME, 538 Groups.ACCOUNT_TYPE, 539 Groups.DATA_SET, 540 Groups.ACCOUNT_TYPE_AND_DATA_SET, 541 Groups.SOURCE_ID, 542 Groups.DIRTY, 543 Groups.VERSION, 544 Groups.RES_PACKAGE, 545 Groups.TITLE, 546 Groups.TITLE_RES, 547 Groups.GROUP_VISIBLE, 548 Groups.SYSTEM_ID, 549 Groups.DELETED, 550 Groups.NOTES, 551 Groups.SHOULD_SYNC, 552 Groups.FAVORITES, 553 Groups.AUTO_ADD, 554 Groups.GROUP_IS_READ_ONLY, 555 Groups.SYNC1, 556 Groups.SYNC2, 557 Groups.SYNC3, 558 Groups.SYNC4, 559 Groups.SUMMARY_COUNT, 560 Groups.SUMMARY_WITH_PHONES, 561 }); 562 } 563 564 public void testAggregateExceptionProjection() { 565 assertProjection(AggregationExceptions.CONTENT_URI, new String[]{ 566 AggregationExceptionColumns._ID, 567 AggregationExceptions.TYPE, 568 AggregationExceptions.RAW_CONTACT_ID1, 569 AggregationExceptions.RAW_CONTACT_ID2, 570 }); 571 } 572 573 public void testSettingsProjection() { 574 assertProjection(Settings.CONTENT_URI, new String[]{ 575 Settings.ACCOUNT_NAME, 576 Settings.ACCOUNT_TYPE, 577 Settings.DATA_SET, 578 Settings.UNGROUPED_VISIBLE, 579 Settings.SHOULD_SYNC, 580 Settings.ANY_UNSYNCED, 581 Settings.UNGROUPED_COUNT, 582 Settings.UNGROUPED_WITH_PHONES, 583 }); 584 } 585 586 public void testStatusUpdatesProjection() { 587 assertProjection(StatusUpdates.CONTENT_URI, new String[]{ 588 PresenceColumns.RAW_CONTACT_ID, 589 StatusUpdates.DATA_ID, 590 StatusUpdates.IM_ACCOUNT, 591 StatusUpdates.IM_HANDLE, 592 StatusUpdates.PROTOCOL, 593 StatusUpdates.CUSTOM_PROTOCOL, 594 StatusUpdates.PRESENCE, 595 StatusUpdates.CHAT_CAPABILITY, 596 StatusUpdates.STATUS, 597 StatusUpdates.STATUS_TIMESTAMP, 598 StatusUpdates.STATUS_RES_PACKAGE, 599 StatusUpdates.STATUS_ICON, 600 StatusUpdates.STATUS_LABEL, 601 }); 602 } 603 604 public void testLiveFoldersProjection() { 605 assertProjection( 606 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "live_folders/contacts"), 607 new String[]{ 608 LiveFolders._ID, 609 LiveFolders.NAME, 610 }); 611 } 612 613 public void testDirectoryProjection() { 614 assertProjection(Directory.CONTENT_URI, new String[]{ 615 Directory._ID, 616 Directory.PACKAGE_NAME, 617 Directory.TYPE_RESOURCE_ID, 618 Directory.DISPLAY_NAME, 619 Directory.DIRECTORY_AUTHORITY, 620 Directory.ACCOUNT_TYPE, 621 Directory.ACCOUNT_NAME, 622 Directory.EXPORT_SUPPORT, 623 Directory.SHORTCUT_SUPPORT, 624 Directory.PHOTO_SUPPORT, 625 }); 626 } 627 628 public void testRawContactsInsert() { 629 ContentValues values = new ContentValues(); 630 631 values.put(RawContacts.ACCOUNT_NAME, "a"); 632 values.put(RawContacts.ACCOUNT_TYPE, "b"); 633 values.put(RawContacts.SOURCE_ID, "c"); 634 values.put(RawContacts.VERSION, 42); 635 values.put(RawContacts.DIRTY, 1); 636 values.put(RawContacts.DELETED, 1); 637 values.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 638 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 639 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 640 values.put(RawContacts.LAST_TIME_CONTACTED, 12345); 641 values.put(RawContacts.STARRED, 1); 642 values.put(RawContacts.SYNC1, "e"); 643 values.put(RawContacts.SYNC2, "f"); 644 values.put(RawContacts.SYNC3, "g"); 645 values.put(RawContacts.SYNC4, "h"); 646 647 Uri rowUri = mResolver.insert(RawContacts.CONTENT_URI, values); 648 long rawContactId = ContentUris.parseId(rowUri); 649 650 assertStoredValues(rowUri, values); 651 assertSelection(RawContacts.CONTENT_URI, values, RawContacts._ID, rawContactId); 652 assertNetworkNotified(true); 653 } 654 655 public void testDataDirectoryWithLookupUri() { 656 ContentValues values = new ContentValues(); 657 658 long rawContactId = createRawContactWithName(); 659 insertPhoneNumber(rawContactId, "555-GOOG-411"); 660 insertEmail(rawContactId, "google@android.com"); 661 662 long contactId = queryContactId(rawContactId); 663 String lookupKey = queryLookupKey(contactId); 664 665 // Complete and valid lookup URI 666 Uri lookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey); 667 Uri dataUri = Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY); 668 669 assertDataRows(dataUri, values); 670 671 // Complete but stale lookup URI 672 lookupUri = ContactsContract.Contacts.getLookupUri(contactId + 1, lookupKey); 673 dataUri = Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY); 674 assertDataRows(dataUri, values); 675 676 // Incomplete lookup URI (lookup key only, no contact ID) 677 dataUri = Uri.withAppendedPath(Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, 678 lookupKey), Contacts.Data.CONTENT_DIRECTORY); 679 assertDataRows(dataUri, values); 680 } 681 682 private void assertDataRows(Uri dataUri, ContentValues values) { 683 Cursor cursor = mResolver.query(dataUri, new String[]{ Data.DATA1 }, null, null, Data._ID); 684 assertEquals(3, cursor.getCount()); 685 cursor.moveToFirst(); 686 values.put(Data.DATA1, "John Doe"); 687 assertCursorValues(cursor, values); 688 689 cursor.moveToNext(); 690 values.put(Data.DATA1, "555-GOOG-411"); 691 assertCursorValues(cursor, values); 692 693 cursor.moveToNext(); 694 values.put(Data.DATA1, "google@android.com"); 695 assertCursorValues(cursor, values); 696 697 cursor.close(); 698 } 699 700 public void testContactEntitiesWithIdBasedUri() { 701 ContentValues values = new ContentValues(); 702 Account account1 = new Account("act1", "actype1"); 703 Account account2 = new Account("act2", "actype2"); 704 705 long rawContactId1 = createRawContactWithName(account1); 706 insertImHandle(rawContactId1, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk"); 707 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", StatusUpdates.IDLE, "Busy", 90, 708 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 709 710 long rawContactId2 = createRawContact(account2); 711 setAggregationException( 712 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 713 714 long contactId = queryContactId(rawContactId1); 715 716 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 717 Uri entityUri = Uri.withAppendedPath(contactUri, Contacts.Entity.CONTENT_DIRECTORY); 718 719 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 720 } 721 722 public void testContactEntitiesWithLookupUri() { 723 ContentValues values = new ContentValues(); 724 Account account1 = new Account("act1", "actype1"); 725 Account account2 = new Account("act2", "actype2"); 726 727 long rawContactId1 = createRawContactWithName(account1); 728 insertImHandle(rawContactId1, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk"); 729 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", StatusUpdates.IDLE, "Busy", 90, 730 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 731 732 long rawContactId2 = createRawContact(account2); 733 setAggregationException( 734 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 735 736 long contactId = queryContactId(rawContactId1); 737 String lookupKey = queryLookupKey(contactId); 738 739 // First try with a matching contact ID 740 Uri contactLookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey); 741 Uri entityUri = Uri.withAppendedPath(contactLookupUri, Contacts.Entity.CONTENT_DIRECTORY); 742 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 743 744 // Now try with a contact ID mismatch 745 contactLookupUri = ContactsContract.Contacts.getLookupUri(contactId + 1, lookupKey); 746 entityUri = Uri.withAppendedPath(contactLookupUri, Contacts.Entity.CONTENT_DIRECTORY); 747 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 748 749 // Now try without an ID altogether 750 contactLookupUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey); 751 entityUri = Uri.withAppendedPath(contactLookupUri, Contacts.Entity.CONTENT_DIRECTORY); 752 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 753 } 754 755 private void assertEntityRows(Uri entityUri, long contactId, long rawContactId1, 756 long rawContactId2) { 757 ContentValues values = new ContentValues(); 758 759 Cursor cursor = mResolver.query(entityUri, null, null, null, 760 Contacts.Entity.RAW_CONTACT_ID + "," + Contacts.Entity.DATA_ID); 761 assertEquals(3, cursor.getCount()); 762 763 // First row - name 764 cursor.moveToFirst(); 765 values.put(Contacts.Entity.CONTACT_ID, contactId); 766 values.put(Contacts.Entity.RAW_CONTACT_ID, rawContactId1); 767 values.put(Contacts.Entity.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 768 values.put(Contacts.Entity.DATA1, "John Doe"); 769 values.put(Contacts.Entity.ACCOUNT_NAME, "act1"); 770 values.put(Contacts.Entity.ACCOUNT_TYPE, "actype1"); 771 values.put(Contacts.Entity.DISPLAY_NAME, "John Doe"); 772 values.put(Contacts.Entity.DISPLAY_NAME_ALTERNATIVE, "Doe, John"); 773 values.put(Contacts.Entity.NAME_RAW_CONTACT_ID, rawContactId1); 774 values.put(Contacts.Entity.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 775 values.put(Contacts.Entity.CONTACT_PRESENCE, StatusUpdates.IDLE); 776 values.put(Contacts.Entity.CONTACT_STATUS, "Busy"); 777 values.putNull(Contacts.Entity.PRESENCE); 778 assertCursorValues(cursor, values); 779 780 // Second row - IM 781 cursor.moveToNext(); 782 values.put(Contacts.Entity.CONTACT_ID, contactId); 783 values.put(Contacts.Entity.RAW_CONTACT_ID, rawContactId1); 784 values.put(Contacts.Entity.MIMETYPE, Im.CONTENT_ITEM_TYPE); 785 values.put(Contacts.Entity.DATA1, "gtalk"); 786 values.put(Contacts.Entity.ACCOUNT_NAME, "act1"); 787 values.put(Contacts.Entity.ACCOUNT_TYPE, "actype1"); 788 values.put(Contacts.Entity.DISPLAY_NAME, "John Doe"); 789 values.put(Contacts.Entity.DISPLAY_NAME_ALTERNATIVE, "Doe, John"); 790 values.put(Contacts.Entity.NAME_RAW_CONTACT_ID, rawContactId1); 791 values.put(Contacts.Entity.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 792 values.put(Contacts.Entity.CONTACT_PRESENCE, StatusUpdates.IDLE); 793 values.put(Contacts.Entity.CONTACT_STATUS, "Busy"); 794 values.put(Contacts.Entity.PRESENCE, StatusUpdates.IDLE); 795 assertCursorValues(cursor, values); 796 797 // Third row - second raw contact, not data 798 cursor.moveToNext(); 799 values.put(Contacts.Entity.CONTACT_ID, contactId); 800 values.put(Contacts.Entity.RAW_CONTACT_ID, rawContactId2); 801 values.putNull(Contacts.Entity.MIMETYPE); 802 values.putNull(Contacts.Entity.DATA_ID); 803 values.putNull(Contacts.Entity.DATA1); 804 values.put(Contacts.Entity.ACCOUNT_NAME, "act2"); 805 values.put(Contacts.Entity.ACCOUNT_TYPE, "actype2"); 806 values.put(Contacts.Entity.DISPLAY_NAME, "John Doe"); 807 values.put(Contacts.Entity.DISPLAY_NAME_ALTERNATIVE, "Doe, John"); 808 values.put(Contacts.Entity.NAME_RAW_CONTACT_ID, rawContactId1); 809 values.put(Contacts.Entity.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 810 values.put(Contacts.Entity.CONTACT_PRESENCE, StatusUpdates.IDLE); 811 values.put(Contacts.Entity.CONTACT_STATUS, "Busy"); 812 values.putNull(Contacts.Entity.PRESENCE); 813 assertCursorValues(cursor, values); 814 815 cursor.close(); 816 } 817 818 public void testDataInsert() { 819 long rawContactId = createRawContactWithName("John", "Doe"); 820 821 ContentValues values = new ContentValues(); 822 putDataValues(values, rawContactId); 823 Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 824 long dataId = ContentUris.parseId(dataUri); 825 826 long contactId = queryContactId(rawContactId); 827 values.put(RawContacts.CONTACT_ID, contactId); 828 assertStoredValues(dataUri, values); 829 830 assertSelection(Data.CONTENT_URI, values, Data._ID, dataId); 831 832 // Access the same data through the directory under RawContacts 833 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 834 Uri rawContactDataUri = 835 Uri.withAppendedPath(rawContactUri, RawContacts.Data.CONTENT_DIRECTORY); 836 assertSelection(rawContactDataUri, values, Data._ID, dataId); 837 838 // Access the same data through the directory under Contacts 839 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 840 Uri contactDataUri = Uri.withAppendedPath(contactUri, Contacts.Data.CONTENT_DIRECTORY); 841 assertSelection(contactDataUri, values, Data._ID, dataId); 842 assertNetworkNotified(true); 843 } 844 845 public void testRawContactDataQuery() { 846 Account account1 = new Account("a", "b"); 847 Account account2 = new Account("c", "d"); 848 long rawContactId1 = createRawContact(account1); 849 Uri dataUri1 = insertStructuredName(rawContactId1, "John", "Doe"); 850 long rawContactId2 = createRawContact(account2); 851 Uri dataUri2 = insertStructuredName(rawContactId2, "Jane", "Doe"); 852 853 Uri uri1 = maybeAddAccountQueryParameters(dataUri1, account1); 854 Uri uri2 = maybeAddAccountQueryParameters(dataUri2, account2); 855 assertStoredValue(uri1, Data._ID, ContentUris.parseId(dataUri1)) ; 856 assertStoredValue(uri2, Data._ID, ContentUris.parseId(dataUri2)) ; 857 } 858 859 public void testPhonesQuery() { 860 861 ContentValues values = new ContentValues(); 862 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 863 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 864 values.put(RawContacts.LAST_TIME_CONTACTED, 12345); 865 values.put(RawContacts.TIMES_CONTACTED, 54321); 866 values.put(RawContacts.STARRED, 1); 867 868 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 869 long rawContactId = ContentUris.parseId(rawContactUri); 870 871 insertStructuredName(rawContactId, "Meghan", "Knox"); 872 Uri uri = insertPhoneNumber(rawContactId, "18004664411"); 873 long phoneId = ContentUris.parseId(uri); 874 875 876 long contactId = queryContactId(rawContactId); 877 values.clear(); 878 values.put(Data._ID, phoneId); 879 values.put(Data.RAW_CONTACT_ID, rawContactId); 880 values.put(RawContacts.CONTACT_ID, contactId); 881 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 882 values.put(Phone.NUMBER, "18004664411"); 883 values.put(Phone.TYPE, Phone.TYPE_HOME); 884 values.putNull(Phone.LABEL); 885 values.put(Contacts.DISPLAY_NAME, "Meghan Knox"); 886 values.put(Contacts.CUSTOM_RINGTONE, "d"); 887 values.put(Contacts.SEND_TO_VOICEMAIL, 1); 888 values.put(Contacts.LAST_TIME_CONTACTED, 12345); 889 values.put(Contacts.TIMES_CONTACTED, 54321); 890 values.put(Contacts.STARRED, 1); 891 892 assertStoredValues(ContentUris.withAppendedId(Phone.CONTENT_URI, phoneId), values); 893 assertSelection(Phone.CONTENT_URI, values, Data._ID, phoneId); 894 } 895 896 public void testPhonesWithMergedContacts() { 897 long rawContactId1 = createRawContact(); 898 insertPhoneNumber(rawContactId1, "123456789", true); 899 900 long rawContactId2 = createRawContact(); 901 insertPhoneNumber(rawContactId2, "123456789", true); 902 903 ContentValues values1 = new ContentValues(); 904 values1.put(Contacts.DISPLAY_NAME, "123456789"); 905 values1.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 906 values1.put(Phone.NUMBER, "123456789"); 907 908 // Two results should come, since they are separate entries anyway. 909 assertStoredValues(Phone.CONTENT_URI, new ContentValues[] {values1, values1}); 910 911 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 912 rawContactId1, rawContactId2); 913 914 assertAggregated(rawContactId1, rawContactId2, "123456789"); 915 916 // Just one result should come, since 917 // - those two numbers have the same phone number 918 // - those two contacts are aggregated 919 assertStoredValues(Phone.CONTENT_URI, values1); 920 } 921 922 public void testPhonesFilterQuery() { 923 long rawContactId1 = createRawContactWithName("Hot", "Tamale", ACCOUNT_1); 924 insertPhoneNumber(rawContactId1, "1-800-466-4411"); 925 926 long rawContactId2 = createRawContactWithName("Chilled", "Guacamole", ACCOUNT_2); 927 insertPhoneNumber(rawContactId2, "1-800-466-5432"); 928 insertPhoneNumber(rawContactId2, "0@example.com", false, Phone.TYPE_PAGER); 929 insertPhoneNumber(rawContactId2, "1@example.com", false, Phone.TYPE_PAGER); 930 931 Uri filterUri1 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "tamale"); 932 ContentValues values = new ContentValues(); 933 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 934 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 935 values.put(Phone.NUMBER, "1-800-466-4411"); 936 values.put(Phone.TYPE, Phone.TYPE_HOME); 937 values.putNull(Phone.LABEL); 938 assertStoredValuesWithProjection(filterUri1, values); 939 940 Uri filterUri2 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "1-800-GOOG-411"); 941 assertStoredValues(filterUri2, values); 942 943 Uri filterUri3 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "18004664"); 944 assertStoredValues(filterUri3, values); 945 946 Uri filterUri4 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "encilada"); 947 assertEquals(0, getCount(filterUri4, null, null)); 948 949 Uri filterUri5 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "*"); 950 assertEquals(0, getCount(filterUri5, null, null)); 951 952 ContentValues values1 = new ContentValues(); 953 values1.put(Contacts.DISPLAY_NAME, "Chilled Guacamole"); 954 values1.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 955 values1.put(Phone.NUMBER, "1-800-466-5432"); 956 values1.put(Phone.TYPE, Phone.TYPE_HOME); 957 values1.putNull(Phone.LABEL); 958 959 ContentValues values2 = new ContentValues(); 960 values2.put(Contacts.DISPLAY_NAME, "Chilled Guacamole"); 961 values2.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 962 values2.put(Phone.NUMBER, "0@example.com"); 963 values2.put(Phone.TYPE, Phone.TYPE_PAGER); 964 values2.putNull(Phone.LABEL); 965 966 ContentValues values3 = new ContentValues(); 967 values3.put(Contacts.DISPLAY_NAME, "Chilled Guacamole"); 968 values3.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 969 values3.put(Phone.NUMBER, "1@example.com"); 970 values3.put(Phone.TYPE, Phone.TYPE_PAGER); 971 values3.putNull(Phone.LABEL); 972 973 Uri filterUri6 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "Chilled"); 974 assertStoredValues(filterUri6, new ContentValues[] {values1, values2, values3} ); 975 } 976 977 public void testPhoneLookup() { 978 ContentValues values = new ContentValues(); 979 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 980 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 981 982 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 983 long rawContactId = ContentUris.parseId(rawContactUri); 984 985 insertStructuredName(rawContactId, "Hot", "Tamale"); 986 insertPhoneNumber(rawContactId, "18004664411"); 987 988 Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411"); 989 990 values.clear(); 991 values.put(PhoneLookup._ID, queryContactId(rawContactId)); 992 values.put(PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 993 values.put(PhoneLookup.NUMBER, "18004664411"); 994 values.put(PhoneLookup.TYPE, Phone.TYPE_HOME); 995 values.putNull(PhoneLookup.LABEL); 996 values.put(PhoneLookup.CUSTOM_RINGTONE, "d"); 997 values.put(PhoneLookup.SEND_TO_VOICEMAIL, 1); 998 assertStoredValues(lookupUri1, values); 999 1000 // In the context that 8004664411 is a valid number, "4664411" as a 1001 // call id should match to both "8004664411" and "+18004664411". 1002 Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "4664411"); 1003 assertEquals(2, getCount(lookupUri2, null, null)); 1004 } 1005 1006 public void testPhoneLookupUseCases() { 1007 ContentValues values = new ContentValues(); 1008 Uri rawContactUri; 1009 long rawContactId; 1010 Uri lookupUri2; 1011 1012 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 1013 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 1014 1015 // International format in contacts 1016 rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1017 rawContactId = ContentUris.parseId(rawContactUri); 1018 1019 insertStructuredName(rawContactId, "Hot", "Tamale"); 1020 insertPhoneNumber(rawContactId, "+1-650-861-0000"); 1021 1022 values.clear(); 1023 1024 // match with international format 1025 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0000"); 1026 assertEquals(1, getCount(lookupUri2, null, null)); 1027 1028 // match with national format 1029 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0000"); 1030 assertEquals(1, getCount(lookupUri2, null, null)); 1031 1032 // National format in contacts 1033 values.clear(); 1034 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 1035 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 1036 rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1037 rawContactId = ContentUris.parseId(rawContactUri); 1038 1039 insertStructuredName(rawContactId, "Hot1", "Tamale"); 1040 insertPhoneNumber(rawContactId, "650-861-0001"); 1041 1042 values.clear(); 1043 1044 // match with international format 1045 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0001"); 1046 assertEquals(2, getCount(lookupUri2, null, null)); 1047 1048 // match with national format 1049 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0001"); 1050 assertEquals(2, getCount(lookupUri2, null, null)); 1051 1052 // Local format in contacts 1053 values.clear(); 1054 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 1055 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 1056 rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1057 rawContactId = ContentUris.parseId(rawContactUri); 1058 1059 insertStructuredName(rawContactId, "Hot2", "Tamale"); 1060 insertPhoneNumber(rawContactId, "861-0002"); 1061 1062 values.clear(); 1063 1064 // match with international format 1065 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0002"); 1066 assertEquals(1, getCount(lookupUri2, null, null)); 1067 1068 // match with national format 1069 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0002"); 1070 assertEquals(1, getCount(lookupUri2, null, null)); 1071 } 1072 1073 public void testPhoneUpdate() { 1074 ContentValues values = new ContentValues(); 1075 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1076 long rawContactId = ContentUris.parseId(rawContactUri); 1077 1078 insertStructuredName(rawContactId, "Hot", "Tamale"); 1079 Uri phoneUri = insertPhoneNumber(rawContactId, "18004664411"); 1080 1081 Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411"); 1082 assertStoredValue(lookupUri1, PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 1083 1084 values.clear(); 1085 values.put(Phone.NUMBER, "18004664422"); 1086 mResolver.update(phoneUri, values, null, null); 1087 1088 Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664422"); 1089 assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 1090 1091 // Setting number to null will remove the phone lookup record 1092 values.clear(); 1093 values.putNull(Phone.NUMBER); 1094 mResolver.update(phoneUri, values, null, null); 1095 1096 assertEquals(0, getCount(lookupUri2, null, null)); 1097 1098 // Let's restore that phone lookup record 1099 values.clear(); 1100 values.put(Phone.NUMBER, "18004664422"); 1101 mResolver.update(phoneUri, values, null, null); 1102 assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 1103 assertNetworkNotified(true); 1104 } 1105 1106 public void testEmailsQuery() { 1107 ContentValues values = new ContentValues(); 1108 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 1109 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 1110 values.put(RawContacts.LAST_TIME_CONTACTED, 12345); 1111 values.put(RawContacts.TIMES_CONTACTED, 54321); 1112 values.put(RawContacts.STARRED, 1); 1113 1114 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1115 long rawContactId = ContentUris.parseId(rawContactUri); 1116 1117 insertStructuredName(rawContactId, "Meghan", "Knox"); 1118 Uri uri = insertEmail(rawContactId, "meghan@acme.com"); 1119 long emailId = ContentUris.parseId(uri); 1120 1121 long contactId = queryContactId(rawContactId); 1122 values.clear(); 1123 values.put(Data._ID, emailId); 1124 values.put(Data.RAW_CONTACT_ID, rawContactId); 1125 values.put(RawContacts.CONTACT_ID, contactId); 1126 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 1127 values.put(Email.DATA, "meghan@acme.com"); 1128 values.put(Email.TYPE, Email.TYPE_HOME); 1129 values.putNull(Email.LABEL); 1130 values.put(Contacts.DISPLAY_NAME, "Meghan Knox"); 1131 values.put(Contacts.CUSTOM_RINGTONE, "d"); 1132 values.put(Contacts.SEND_TO_VOICEMAIL, 1); 1133 values.put(Contacts.LAST_TIME_CONTACTED, 12345); 1134 values.put(Contacts.TIMES_CONTACTED, 54321); 1135 values.put(Contacts.STARRED, 1); 1136 1137 assertStoredValues(ContentUris.withAppendedId(Email.CONTENT_URI, emailId), values); 1138 assertSelection(Email.CONTENT_URI, values, Data._ID, emailId); 1139 } 1140 1141 public void testEmailsLookupQuery() { 1142 long rawContactId = createRawContactWithName("Hot", "Tamale"); 1143 insertEmail(rawContactId, "tamale@acme.com"); 1144 1145 Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "tamale@acme.com"); 1146 ContentValues values = new ContentValues(); 1147 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 1148 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 1149 values.put(Email.DATA, "tamale@acme.com"); 1150 values.put(Email.TYPE, Email.TYPE_HOME); 1151 values.putNull(Email.LABEL); 1152 assertStoredValues(filterUri1, values); 1153 1154 Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "Ta<TaMale@acme.com>"); 1155 assertStoredValues(filterUri2, values); 1156 1157 Uri filterUri3 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "encilada@acme.com"); 1158 assertEquals(0, getCount(filterUri3, null, null)); 1159 } 1160 1161 public void testEmailsFilterQuery() { 1162 long rawContactId1 = createRawContactWithName("Hot", "Tamale", ACCOUNT_1); 1163 insertEmail(rawContactId1, "tamale@acme.com"); 1164 insertEmail(rawContactId1, "tamale@acme.com"); 1165 1166 long rawContactId2 = createRawContactWithName("Hot", "Tamale", ACCOUNT_2); 1167 insertEmail(rawContactId2, "tamale@acme.com"); 1168 1169 Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tam"); 1170 ContentValues values = new ContentValues(); 1171 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 1172 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 1173 values.put(Email.DATA, "tamale@acme.com"); 1174 values.put(Email.TYPE, Email.TYPE_HOME); 1175 values.putNull(Email.LABEL); 1176 assertStoredValuesWithProjection(filterUri1, values); 1177 1178 Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hot"); 1179 assertStoredValuesWithProjection(filterUri2, values); 1180 1181 Uri filterUri3 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hot tamale"); 1182 assertStoredValuesWithProjection(filterUri3, values); 1183 1184 Uri filterUri4 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tamale@acme"); 1185 assertStoredValuesWithProjection(filterUri4, values); 1186 1187 Uri filterUri5 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "encilada"); 1188 assertEquals(0, getCount(filterUri5, null, null)); 1189 } 1190 1191 /** 1192 * Tests if ContactsProvider2 returns addresses according to registration order. 1193 */ 1194 public void testEmailFilterDefaultSortOrder() { 1195 long rawContactId1 = createRawContact(); 1196 insertEmail(rawContactId1, "address1@email.com"); 1197 insertEmail(rawContactId1, "address2@email.com"); 1198 insertEmail(rawContactId1, "address3@email.com"); 1199 ContentValues v1 = new ContentValues(); 1200 v1.put(Email.ADDRESS, "address1@email.com"); 1201 ContentValues v2 = new ContentValues(); 1202 v2.put(Email.ADDRESS, "address2@email.com"); 1203 ContentValues v3 = new ContentValues(); 1204 v3.put(Email.ADDRESS, "address3@email.com"); 1205 1206 Uri filterUri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "address"); 1207 assertStoredValuesOrderly(filterUri, new ContentValues[] { v1, v2, v3 }); 1208 } 1209 1210 /** 1211 * Tests if ContactsProvider2 returns primary addresses before the other addresses. 1212 */ 1213 public void testEmailFilterPrimaryAddress() { 1214 long rawContactId1 = createRawContact(); 1215 insertEmail(rawContactId1, "address1@email.com"); 1216 insertEmail(rawContactId1, "address2@email.com", true); 1217 ContentValues v1 = new ContentValues(); 1218 v1.put(Email.ADDRESS, "address1@email.com"); 1219 ContentValues v2 = new ContentValues(); 1220 v2.put(Email.ADDRESS, "address2@email.com"); 1221 1222 Uri filterUri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "address"); 1223 assertStoredValuesOrderly(filterUri, new ContentValues[] { v2, v1 }); 1224 } 1225 1226 /** 1227 * Tests if ContactsProvider2 has email address associated with a primary account before the 1228 * other address. 1229 */ 1230 public void testEmailFilterPrimaryAccount() { 1231 long rawContactId1 = createRawContact(ACCOUNT_1); 1232 insertEmail(rawContactId1, "account1@email.com"); 1233 long rawContactId2 = createRawContact(ACCOUNT_2); 1234 insertEmail(rawContactId2, "account2@email.com"); 1235 ContentValues v1 = new ContentValues(); 1236 v1.put(Email.ADDRESS, "account1@email.com"); 1237 ContentValues v2 = new ContentValues(); 1238 v2.put(Email.ADDRESS, "account2@email.com"); 1239 1240 Uri filterUri1 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc") 1241 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, ACCOUNT_1.name) 1242 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE, ACCOUNT_1.type) 1243 .build(); 1244 assertStoredValuesOrderly(filterUri1, new ContentValues[] { v1, v2 }); 1245 1246 Uri filterUri2 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc") 1247 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, ACCOUNT_2.name) 1248 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE, ACCOUNT_2.type) 1249 .build(); 1250 assertStoredValuesOrderly(filterUri2, new ContentValues[] { v2, v1 }); 1251 1252 // Just with PRIMARY_ACCOUNT_NAME 1253 Uri filterUri3 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc") 1254 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, ACCOUNT_1.name) 1255 .build(); 1256 assertStoredValuesOrderly(filterUri3, new ContentValues[] { v1, v2 }); 1257 1258 Uri filterUri4 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc") 1259 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, ACCOUNT_2.name) 1260 .build(); 1261 assertStoredValuesOrderly(filterUri4, new ContentValues[] { v2, v1 }); 1262 } 1263 1264 /** Tests {@link DataUsageFeedback} correctly promotes a data row instead of a raw contact. */ 1265 public void testEmailFilterSortOrderWithFeedback() { 1266 long rawContactId1 = createRawContact(); 1267 String address1 = "address1@email.com"; 1268 insertEmail(rawContactId1, address1); 1269 long rawContactId2 = createRawContact(); 1270 String address2 = "address2@email.com"; 1271 insertEmail(rawContactId2, address2); 1272 String address3 = "address3@email.com"; 1273 ContentUris.parseId(insertEmail(rawContactId2, address3)); 1274 1275 ContentValues v1 = new ContentValues(); 1276 v1.put(Email.ADDRESS, "address1@email.com"); 1277 ContentValues v2 = new ContentValues(); 1278 v2.put(Email.ADDRESS, "address2@email.com"); 1279 ContentValues v3 = new ContentValues(); 1280 v3.put(Email.ADDRESS, "address3@email.com"); 1281 1282 Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "address"); 1283 Uri filterUri2 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("address") 1284 .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, 1285 DataUsageFeedback.USAGE_TYPE_CALL) 1286 .build(); 1287 Uri filterUri3 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("address") 1288 .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, 1289 DataUsageFeedback.USAGE_TYPE_LONG_TEXT) 1290 .build(); 1291 Uri filterUri4 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("address") 1292 .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, 1293 DataUsageFeedback.USAGE_TYPE_SHORT_TEXT) 1294 .build(); 1295 assertStoredValuesOrderly(filterUri1, new ContentValues[] { v1, v2, v3 }); 1296 assertStoredValuesOrderly(filterUri2, new ContentValues[] { v1, v2, v3 }); 1297 assertStoredValuesOrderly(filterUri3, new ContentValues[] { v1, v2, v3 }); 1298 assertStoredValuesOrderly(filterUri4, new ContentValues[] { v1, v2, v3 }); 1299 1300 sendFeedback(address3, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, v3); 1301 1302 // account3@email.com should be the first. account2@email.com should also be promoted as 1303 // it has same contact id. 1304 assertStoredValuesOrderly(filterUri1, new ContentValues[] { v3, v1, v2 }); 1305 assertStoredValuesOrderly(filterUri3, new ContentValues[] { v3, v1, v2 }); 1306 } 1307 1308 /** 1309 * Tests {@link DataUsageFeedback} correctly bucketize contacts using each 1310 * {@link DataUsageStatColumns#LAST_TIME_USED} 1311 */ 1312 public void testEmailFilterSortOrderWithOldHistory() { 1313 long rawContactId1 = createRawContact(); 1314 long dataId1 = ContentUris.parseId(insertEmail(rawContactId1, "address1@email.com")); 1315 long dataId2 = ContentUris.parseId(insertEmail(rawContactId1, "address2@email.com")); 1316 long dataId3 = ContentUris.parseId(insertEmail(rawContactId1, "address3@email.com")); 1317 long dataId4 = ContentUris.parseId(insertEmail(rawContactId1, "address4@email.com")); 1318 1319 Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "address"); 1320 1321 ContentValues v1 = new ContentValues(); 1322 v1.put(Email.ADDRESS, "address1@email.com"); 1323 ContentValues v2 = new ContentValues(); 1324 v2.put(Email.ADDRESS, "address2@email.com"); 1325 ContentValues v3 = new ContentValues(); 1326 v3.put(Email.ADDRESS, "address3@email.com"); 1327 ContentValues v4 = new ContentValues(); 1328 v4.put(Email.ADDRESS, "address4@email.com"); 1329 1330 final ContactsProvider2 provider = (ContactsProvider2) getProvider(); 1331 1332 long nowInMillis = System.currentTimeMillis(); 1333 long yesterdayInMillis = (nowInMillis - 24 * 60 * 60 * 1000); 1334 long sevenDaysAgoInMillis = (nowInMillis - 7 * 24 * 60 * 60 * 1000); 1335 long oneYearAgoInMillis = (nowInMillis - 365L * 24 * 60 * 60 * 1000); 1336 1337 // address4 is contacted just once yesterday. 1338 provider.updateDataUsageStat(Arrays.asList(dataId4), 1339 DataUsageFeedback.USAGE_TYPE_LONG_TEXT, yesterdayInMillis); 1340 1341 // address3 is contacted twice 1 week ago. 1342 provider.updateDataUsageStat(Arrays.asList(dataId3), 1343 DataUsageFeedback.USAGE_TYPE_LONG_TEXT, sevenDaysAgoInMillis); 1344 provider.updateDataUsageStat(Arrays.asList(dataId3), 1345 DataUsageFeedback.USAGE_TYPE_LONG_TEXT, sevenDaysAgoInMillis); 1346 1347 // address2 is contacted three times 1 year ago. 1348 provider.updateDataUsageStat(Arrays.asList(dataId2), 1349 DataUsageFeedback.USAGE_TYPE_LONG_TEXT, oneYearAgoInMillis); 1350 provider.updateDataUsageStat(Arrays.asList(dataId2), 1351 DataUsageFeedback.USAGE_TYPE_LONG_TEXT, oneYearAgoInMillis); 1352 provider.updateDataUsageStat(Arrays.asList(dataId2), 1353 DataUsageFeedback.USAGE_TYPE_LONG_TEXT, oneYearAgoInMillis); 1354 1355 // auto-complete should prefer recently contacted methods 1356 assertStoredValuesOrderly(filterUri1, new ContentValues[] { v4, v3, v2, v1 }); 1357 1358 // Pretend address2 is contacted right now 1359 provider.updateDataUsageStat(Arrays.asList(dataId2), 1360 DataUsageFeedback.USAGE_TYPE_LONG_TEXT, nowInMillis); 1361 1362 // Now address2 is the most recently used address 1363 assertStoredValuesOrderly(filterUri1, new ContentValues[] { v2, v4, v3, v1 }); 1364 1365 // Pretend address1 is contacted right now 1366 provider.updateDataUsageStat(Arrays.asList(dataId1), 1367 DataUsageFeedback.USAGE_TYPE_LONG_TEXT, nowInMillis); 1368 1369 // address2 is preferred to address1 as address2 is used 4 times in total 1370 assertStoredValuesOrderly(filterUri1, new ContentValues[] { v2, v1, v4, v3 }); 1371 } 1372 1373 public void testPostalsQuery() { 1374 long rawContactId = createRawContactWithName("Alice", "Nextore"); 1375 Uri dataUri = insertPostalAddress(rawContactId, "1600 Amphiteatre Ave, Mountain View"); 1376 long dataId = ContentUris.parseId(dataUri); 1377 1378 long contactId = queryContactId(rawContactId); 1379 ContentValues values = new ContentValues(); 1380 values.put(Data._ID, dataId); 1381 values.put(Data.RAW_CONTACT_ID, rawContactId); 1382 values.put(RawContacts.CONTACT_ID, contactId); 1383 values.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE); 1384 values.put(StructuredPostal.FORMATTED_ADDRESS, "1600 Amphiteatre Ave, Mountain View"); 1385 values.put(Contacts.DISPLAY_NAME, "Alice Nextore"); 1386 1387 assertStoredValues(ContentUris.withAppendedId(StructuredPostal.CONTENT_URI, dataId), 1388 values); 1389 assertSelection(StructuredPostal.CONTENT_URI, values, Data._ID, dataId); 1390 } 1391 1392 public void testQueryContactData() { 1393 ContentValues values = new ContentValues(); 1394 long contactId = createContact(values, "John", "Doe", 1395 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 1396 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO); 1397 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1398 1399 assertStoredValues(contactUri, values); 1400 assertSelection(Contacts.CONTENT_URI, values, Contacts._ID, contactId); 1401 } 1402 1403 public void testQueryContactWithStatusUpdate() { 1404 ContentValues values = new ContentValues(); 1405 long contactId = createContact(values, "John", "Doe", 1406 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 1407 StatusUpdates.CAPABILITY_HAS_CAMERA); 1408 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 1409 values.put(Contacts.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 1410 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1411 assertStoredValuesWithProjection(contactUri, values); 1412 assertSelectionWithProjection(Contacts.CONTENT_URI, values, Contacts._ID, contactId); 1413 } 1414 1415 public void testQueryContactFilterByName() { 1416 ContentValues values = new ContentValues(); 1417 long rawContactId = createRawContact(values, "18004664411", 1418 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 1419 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO | 1420 StatusUpdates.CAPABILITY_HAS_VOICE); 1421 1422 ContentValues nameValues = new ContentValues(); 1423 nameValues.put(StructuredName.GIVEN_NAME, "Stu"); 1424 nameValues.put(StructuredName.FAMILY_NAME, "Goulash"); 1425 nameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "goo"); 1426 nameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "LASH"); 1427 Uri nameUri = insertStructuredName(rawContactId, nameValues); 1428 1429 long contactId = queryContactId(rawContactId); 1430 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 1431 1432 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goulash"); 1433 assertStoredValuesWithProjection(filterUri1, values); 1434 1435 assertContactFilter(contactId, "goolash"); 1436 assertContactFilter(contactId, "lash"); 1437 1438 assertContactFilterNoResult("goolish"); 1439 1440 // Phonetic name with given/family reversed should not match 1441 assertContactFilterNoResult("lashgoo"); 1442 1443 nameValues.clear(); 1444 nameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "ga"); 1445 nameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "losh"); 1446 1447 mResolver.update(nameUri, nameValues, null, null); 1448 1449 assertContactFilter(contactId, "galosh"); 1450 1451 assertContactFilterNoResult("goolish"); 1452 } 1453 1454 public void testQueryContactFilterByEmailAddress() { 1455 ContentValues values = new ContentValues(); 1456 long rawContactId = createRawContact(values, "18004664411", 1457 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 1458 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO | 1459 StatusUpdates.CAPABILITY_HAS_VOICE); 1460 1461 insertStructuredName(rawContactId, "James", "Bond"); 1462 1463 long contactId = queryContactId(rawContactId); 1464 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 1465 1466 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goog411@acme.com"); 1467 assertStoredValuesWithProjection(filterUri1, values); 1468 1469 assertContactFilter(contactId, "goog"); 1470 assertContactFilter(contactId, "goog411"); 1471 assertContactFilter(contactId, "goog411@"); 1472 assertContactFilter(contactId, "goog411@acme"); 1473 assertContactFilter(contactId, "goog411@acme.com"); 1474 1475 assertContactFilterNoResult("goog411@acme.combo"); 1476 assertContactFilterNoResult("goog411@le.com"); 1477 assertContactFilterNoResult("goolish"); 1478 } 1479 1480 public void testQueryContactFilterByPhoneNumber() { 1481 ContentValues values = new ContentValues(); 1482 long rawContactId = createRawContact(values, "18004664411", 1483 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 1484 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO | 1485 StatusUpdates.CAPABILITY_HAS_VOICE); 1486 1487 insertStructuredName(rawContactId, "James", "Bond"); 1488 1489 long contactId = queryContactId(rawContactId); 1490 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 1491 1492 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "18004664411"); 1493 assertStoredValuesWithProjection(filterUri1, values); 1494 1495 assertContactFilter(contactId, "18004664411"); 1496 assertContactFilter(contactId, "1800466"); 1497 assertContactFilter(contactId, "+18004664411"); 1498 assertContactFilter(contactId, "8004664411"); 1499 1500 assertContactFilterNoResult("78004664411"); 1501 assertContactFilterNoResult("18004664412"); 1502 assertContactFilterNoResult("8884664411"); 1503 } 1504 1505 /** 1506 * Checks ContactsProvider2 works well with strequent Uris. The provider should return starred 1507 * contacts and frequently used contacts. 1508 */ 1509 public void testQueryContactStrequent() { 1510 ContentValues values1 = new ContentValues(); 1511 final String email1 = "a@acme.com"; 1512 final int timesContacted1 = 0; 1513 createContact(values1, "Noah", "Tever", "18004664411", 1514 email1, StatusUpdates.OFFLINE, timesContacted1, 0, 0, 1515 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO); 1516 final String phoneNumber2 = "18004664412"; 1517 ContentValues values2 = new ContentValues(); 1518 createContact(values2, "Sam", "Times", phoneNumber2, 1519 "b@acme.com", StatusUpdates.INVISIBLE, 3, 0, 0, 1520 StatusUpdates.CAPABILITY_HAS_CAMERA); 1521 ContentValues values3 = new ContentValues(); 1522 final String phoneNumber3 = "18004664413"; 1523 final int timesContacted3 = 5; 1524 createContact(values3, "Lotta", "Calling", phoneNumber3, 1525 "c@acme.com", StatusUpdates.AWAY, timesContacted3, 0, 0, 1526 StatusUpdates.CAPABILITY_HAS_VIDEO); 1527 ContentValues values4 = new ContentValues(); 1528 final long rawContactId4 = createRawContact(values4, "Fay", "Veritt", null, 1529 "d@acme.com", StatusUpdates.AVAILABLE, 0, 1, 0, 1530 StatusUpdates.CAPABILITY_HAS_VIDEO | StatusUpdates.CAPABILITY_HAS_VOICE); 1531 1532 // Starred contacts should be returned. TIMES_CONTACTED should be ignored and only data 1533 // usage feedback should be used for "frequently contacted" listing. 1534 assertStoredValues(Contacts.CONTENT_STREQUENT_URI, values4); 1535 1536 // Send feedback for the 3rd phone number, pretending we called that person via phone. 1537 sendFeedback(phoneNumber3, DataUsageFeedback.USAGE_TYPE_CALL, values3); 1538 1539 // After the feedback, 3rd contact should be shown after starred one. 1540 assertStoredValuesOrderly(Contacts.CONTENT_STREQUENT_URI, 1541 new ContentValues[] { values4, values3 }); 1542 1543 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1); 1544 // Twice. 1545 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1); 1546 1547 // After the feedback, 1st and 3rd contacts should be shown after starred one. 1548 assertStoredValuesOrderly(Contacts.CONTENT_STREQUENT_URI, 1549 new ContentValues[] { values4, values1, values3 }); 1550 1551 // With phone-only parameter, 1st and 4th contacts shouldn't be returned because: 1552 // 1st: feedbacks are only about email, not about phone call. 1553 // 4th: it has no phone number though starred. 1554 Uri phoneOnlyStrequentUri = Contacts.CONTENT_STREQUENT_URI.buildUpon() 1555 .appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "true") 1556 .build(); 1557 assertStoredValuesOrderly(phoneOnlyStrequentUri, new ContentValues[] { values3 }); 1558 1559 // Now the 4th contact has a phone number. 1560 insertPhoneNumber(rawContactId4, "18004664414"); 1561 1562 // Phone only strequent should return 4th contact. 1563 assertStoredValuesOrderly(phoneOnlyStrequentUri, new ContentValues[] { values4, values3 }); 1564 1565 // Send feedback for the 2rd phone number, pretending we send the person a SMS message. 1566 sendFeedback(phoneNumber2, DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, values1); 1567 1568 // SMS feedback shouldn't affect phone-only results. 1569 assertStoredValuesOrderly(phoneOnlyStrequentUri, new ContentValues[] { values4, values3 }); 1570 1571 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_STREQUENT_FILTER_URI, "fay"); 1572 assertStoredValues(filterUri, values4); 1573 } 1574 1575 /** 1576 * Checks ContactsProvider2 works well with frequent Uri. The provider should return frequently 1577 * contacted person ordered by number of times contacted. 1578 */ 1579 public void testQueryContactFrequent() { 1580 ContentValues values1 = new ContentValues(); 1581 final String email1 = "a@acme.com"; 1582 createContact(values1, "Noah", "Tever", "18004664411", 1583 email1, StatusUpdates.OFFLINE, 0, 0, 0, 0); 1584 ContentValues values2 = new ContentValues(); 1585 final String email2 = "b@acme.com"; 1586 createContact(values2, "Sam", "Times", "18004664412", 1587 email2, StatusUpdates.INVISIBLE, 0, 0, 0, 0); 1588 ContentValues values3 = new ContentValues(); 1589 final String phoneNumber3 = "18004664413"; 1590 final long contactId3 = createContact(values3, "Lotta", "Calling", phoneNumber3, 1591 "c@acme.com", StatusUpdates.AWAY, 0, 1, 0, 0); 1592 ContentValues values4 = new ContentValues(); 1593 createContact(values4, "Fay", "Veritt", "18004664414", 1594 "d@acme.com", StatusUpdates.AVAILABLE, 0, 1, 0, 0); 1595 1596 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1); 1597 1598 assertStoredValues(Contacts.CONTENT_FREQUENT_URI, values1); 1599 1600 // Pretend email was sent to the address twice. 1601 sendFeedback(email2, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values2); 1602 sendFeedback(email2, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values2); 1603 1604 assertStoredValues(Contacts.CONTENT_FREQUENT_URI, new ContentValues[] {values2, values1}); 1605 1606 // Three times 1607 sendFeedback(phoneNumber3, DataUsageFeedback.USAGE_TYPE_CALL, values3); 1608 sendFeedback(phoneNumber3, DataUsageFeedback.USAGE_TYPE_CALL, values3); 1609 sendFeedback(phoneNumber3, DataUsageFeedback.USAGE_TYPE_CALL, values3); 1610 1611 assertStoredValues(Contacts.CONTENT_FREQUENT_URI, 1612 new ContentValues[] {values3, values2, values1}); 1613 1614 // Test it works with selection/selectionArgs 1615 assertStoredValues(Contacts.CONTENT_FREQUENT_URI, 1616 Contacts.STARRED + "=?", new String[] {"0"}, 1617 new ContentValues[] {values2, values1}); 1618 assertStoredValues(Contacts.CONTENT_FREQUENT_URI, 1619 Contacts.STARRED + "=?", new String[] {"1"}, 1620 new ContentValues[] {values3}); 1621 1622 values3.put(Contacts.STARRED, 0); 1623 assertEquals(1, 1624 mResolver.update(Uri.withAppendedPath(Contacts.CONTENT_URI, 1625 String.valueOf(contactId3)), 1626 values3, null, null)); 1627 assertStoredValues(Contacts.CONTENT_FREQUENT_URI, 1628 Contacts.STARRED + "=?", new String[] {"0"}, 1629 new ContentValues[] {values3, values2, values1}); 1630 assertStoredValues(Contacts.CONTENT_FREQUENT_URI, 1631 Contacts.STARRED + "=?", new String[] {"1"}, 1632 new ContentValues[] {}); 1633 } 1634 1635 public void testQueryContactGroup() { 1636 long groupId = createGroup(null, "testGroup", "Test Group"); 1637 1638 ContentValues values1 = new ContentValues(); 1639 createContact(values1, "Best", "West", "18004664411", 1640 "west@acme.com", StatusUpdates.OFFLINE, 0, 0, groupId, 1641 StatusUpdates.CAPABILITY_HAS_CAMERA); 1642 1643 ContentValues values2 = new ContentValues(); 1644 createContact(values2, "Rest", "East", "18004664422", 1645 "east@acme.com", StatusUpdates.AVAILABLE, 0, 0, 0, 1646 StatusUpdates.CAPABILITY_HAS_VOICE); 1647 1648 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group"); 1649 Cursor c = mResolver.query(filterUri1, null, null, null, Contacts._ID); 1650 assertEquals(1, c.getCount()); 1651 c.moveToFirst(); 1652 assertCursorValues(c, values1); 1653 c.close(); 1654 1655 Uri filterUri2 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group"); 1656 c = mResolver.query(filterUri2, null, Contacts.DISPLAY_NAME + "=?", 1657 new String[] { "Best West" }, Contacts._ID); 1658 assertEquals(1, c.getCount()); 1659 c.close(); 1660 1661 Uri filterUri3 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Next Group"); 1662 c = mResolver.query(filterUri3, null, null, null, Contacts._ID); 1663 assertEquals(0, c.getCount()); 1664 c.close(); 1665 } 1666 1667 private void expectSecurityException(String failureMessage, Uri uri, String[] projection, 1668 String selection, String[] selectionArgs, String sortOrder) { 1669 Cursor c = null; 1670 try { 1671 c = mResolver.query(uri, projection, selection, selectionArgs, sortOrder); 1672 fail(failureMessage); 1673 } catch (SecurityException expected) { 1674 // The security exception is expected to occur because we're missing a permission. 1675 } finally { 1676 if (c != null) { 1677 c.close(); 1678 } 1679 } 1680 } 1681 1682 public void testQueryProfileRequiresReadPermission() { 1683 mActor.removePermissions("android.permission.READ_PROFILE"); 1684 1685 createBasicProfileContact(new ContentValues()); 1686 1687 // Case 1: Retrieving profile contact. 1688 expectSecurityException( 1689 "Querying for the profile without READ_PROFILE access should fail.", 1690 Profile.CONTENT_URI, null, null, null, Contacts._ID); 1691 1692 // Case 2: Retrieving profile data. 1693 expectSecurityException( 1694 "Querying for the profile data without READ_PROFILE access should fail.", 1695 Profile.CONTENT_URI.buildUpon().appendPath("data").build(), 1696 null, null, null, Contacts._ID); 1697 1698 // Case 3: Retrieving profile entities. 1699 expectSecurityException( 1700 "Querying for the profile entities without READ_PROFILE access should fail.", 1701 Profile.CONTENT_URI.buildUpon() 1702 .appendPath("entities").build(), null, null, null, Contacts._ID); 1703 } 1704 1705 public void testQueryProfileByContactIdRequiresReadPermission() { 1706 long profileRawContactId = createBasicProfileContact(new ContentValues()); 1707 long profileContactId = queryContactId(profileRawContactId); 1708 1709 mActor.removePermissions("android.permission.READ_PROFILE"); 1710 1711 // A query for the profile contact by ID should fail. 1712 expectSecurityException( 1713 "Querying for the profile by contact ID without READ_PROFILE access should fail.", 1714 ContentUris.withAppendedId(Contacts.CONTENT_URI, profileContactId), 1715 null, null, null, Contacts._ID); 1716 } 1717 1718 public void testQueryProfileByRawContactIdRequiresReadPermission() { 1719 long profileRawContactId = createBasicProfileContact(new ContentValues()); 1720 1721 // Remove profile read permission and attempt to retrieve the raw contact. 1722 mActor.removePermissions("android.permission.READ_PROFILE"); 1723 expectSecurityException( 1724 "Querying for the raw contact profile without READ_PROFILE access should fail.", 1725 ContentUris.withAppendedId(RawContacts.CONTENT_URI, 1726 profileRawContactId), null, null, null, RawContacts._ID); 1727 } 1728 1729 public void testQueryProfileRawContactRequiresReadPermission() { 1730 long profileRawContactId = createBasicProfileContact(new ContentValues()); 1731 1732 // Remove profile read permission and attempt to retrieve the profile's raw contact data. 1733 mActor.removePermissions("android.permission.READ_PROFILE"); 1734 1735 // Case 1: Retrieve the overall raw contact set for the profile. 1736 expectSecurityException( 1737 "Querying for the raw contact profile without READ_PROFILE access should fail.", 1738 Profile.CONTENT_RAW_CONTACTS_URI, null, null, null, null); 1739 1740 // Case 2: Retrieve the raw contact profile data for the inserted raw contact ID. 1741 expectSecurityException( 1742 "Querying for the raw profile data without READ_PROFILE access should fail.", 1743 ContentUris.withAppendedId( 1744 Profile.CONTENT_RAW_CONTACTS_URI, profileRawContactId).buildUpon() 1745 .appendPath("data").build(), null, null, null, null); 1746 1747 // Case 3: Retrieve the raw contact profile entity for the inserted raw contact ID. 1748 expectSecurityException( 1749 "Querying for the raw profile entities without READ_PROFILE access should fail.", 1750 ContentUris.withAppendedId( 1751 Profile.CONTENT_RAW_CONTACTS_URI, profileRawContactId).buildUpon() 1752 .appendPath("entity").build(), null, null, null, null); 1753 } 1754 1755 public void testQueryProfileDataByDataIdRequiresReadPermission() { 1756 createBasicProfileContact(new ContentValues()); 1757 Cursor c = mResolver.query(Profile.CONTENT_URI.buildUpon().appendPath("data").build(), 1758 new String[]{Data._ID, Data.MIMETYPE}, null, null, null); 1759 assertEquals(4, c.getCount()); // Photo, phone, email, name. 1760 c.moveToFirst(); 1761 long profileDataId = c.getLong(0); 1762 c.close(); 1763 1764 // Remove profile read permission and attempt to retrieve the data 1765 mActor.removePermissions("android.permission.READ_PROFILE"); 1766 expectSecurityException( 1767 "Querying for the data in the profile without READ_PROFILE access should fail.", 1768 ContentUris.withAppendedId(Data.CONTENT_URI, profileDataId), 1769 null, null, null, null); 1770 } 1771 1772 public void testQueryProfileDataRequiresReadPermission() { 1773 createBasicProfileContact(new ContentValues()); 1774 1775 // Remove profile read permission and attempt to retrieve all profile data. 1776 mActor.removePermissions("android.permission.READ_PROFILE"); 1777 expectSecurityException( 1778 "Querying for the data in the profile without READ_PROFILE access should fail.", 1779 Profile.CONTENT_URI.buildUpon().appendPath("data").build(), 1780 null, null, null, null); 1781 } 1782 1783 public void testInsertProfileRequiresWritePermission() { 1784 mActor.removePermissions("android.permission.WRITE_PROFILE"); 1785 1786 // Creating a non-profile contact should be fine. 1787 createBasicNonProfileContact(new ContentValues()); 1788 1789 // Creating a profile contact should throw an exception. 1790 try { 1791 createBasicProfileContact(new ContentValues()); 1792 fail("Creating a profile contact should fail without WRITE_PROFILE access."); 1793 } catch (SecurityException expected) { 1794 } 1795 } 1796 1797 public void testInsertProfileDataRequiresWritePermission() { 1798 long profileRawContactId = createBasicProfileContact(new ContentValues()); 1799 1800 mActor.removePermissions("android.permission.WRITE_PROFILE"); 1801 try { 1802 insertEmail(profileRawContactId, "foo@bar.net", false); 1803 fail("Inserting data into a profile contact should fail without WRITE_PROFILE access."); 1804 } catch (SecurityException expected) { 1805 } 1806 } 1807 1808 public void testUpdateDataDoesNotRequireProfilePermission() { 1809 mActor.removePermissions("android.permission.READ_PROFILE"); 1810 mActor.removePermissions("android.permission.WRITE_PROFILE"); 1811 1812 // Create a non-profile contact. 1813 long rawContactId = createRawContactWithName("Domo", "Arigato"); 1814 long dataId = getStoredLongValue(Data.CONTENT_URI, 1815 Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?", 1816 new String[]{String.valueOf(rawContactId), StructuredName.CONTENT_ITEM_TYPE}, 1817 Data._ID); 1818 1819 // Updates its name using a selection. 1820 ContentValues values = new ContentValues(); 1821 values.put(StructuredName.GIVEN_NAME, "Bob"); 1822 values.put(StructuredName.FAMILY_NAME, "Blob"); 1823 mResolver.update(Data.CONTENT_URI, values, Data._ID + "=?", 1824 new String[]{String.valueOf(dataId)}); 1825 1826 // Check that the update went through. 1827 assertStoredValues(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), values); 1828 } 1829 1830 public void testQueryContactThenProfile() { 1831 ContentValues profileValues = new ContentValues(); 1832 long profileRawContactId = createBasicProfileContact(profileValues); 1833 long profileContactId = queryContactId(profileRawContactId); 1834 1835 ContentValues nonProfileValues = new ContentValues(); 1836 long nonProfileRawContactId = createBasicNonProfileContact(nonProfileValues); 1837 long nonProfileContactId = queryContactId(nonProfileRawContactId); 1838 1839 assertStoredValues(Contacts.CONTENT_URI, nonProfileValues); 1840 assertSelection(Contacts.CONTENT_URI, nonProfileValues, Contacts._ID, nonProfileContactId); 1841 1842 assertStoredValues(Profile.CONTENT_URI, profileValues); 1843 } 1844 1845 public void testQueryContactExcludeProfile() { 1846 // Create a profile contact (it should not be returned by the general contact URI). 1847 createBasicProfileContact(new ContentValues()); 1848 1849 // Create a non-profile contact - this should be returned. 1850 ContentValues nonProfileValues = new ContentValues(); 1851 createBasicNonProfileContact(nonProfileValues); 1852 1853 assertStoredValues(Contacts.CONTENT_URI, new ContentValues[] {nonProfileValues}); 1854 } 1855 1856 public void testQueryProfile() { 1857 ContentValues profileValues = new ContentValues(); 1858 createBasicProfileContact(profileValues); 1859 1860 assertStoredValues(Profile.CONTENT_URI, profileValues); 1861 } 1862 1863 private ContentValues[] getExpectedProfileDataValues() { 1864 // Expected photo data values (only field is the photo BLOB, which we can't check). 1865 ContentValues photoRow = new ContentValues(); 1866 photoRow.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 1867 1868 // Expected phone data values. 1869 ContentValues phoneRow = new ContentValues(); 1870 phoneRow.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1871 phoneRow.put(Phone.NUMBER, "18005554411"); 1872 1873 // Expected email data values. 1874 ContentValues emailRow = new ContentValues(); 1875 emailRow.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 1876 emailRow.put(Email.ADDRESS, "mia.prophyl@acme.com"); 1877 1878 // Expected name data values. 1879 ContentValues nameRow = new ContentValues(); 1880 nameRow.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 1881 nameRow.put(StructuredName.DISPLAY_NAME, "Mia Prophyl"); 1882 nameRow.put(StructuredName.GIVEN_NAME, "Mia"); 1883 nameRow.put(StructuredName.FAMILY_NAME, "Prophyl"); 1884 1885 return new ContentValues[]{photoRow, phoneRow, emailRow, nameRow}; 1886 } 1887 1888 public void testQueryProfileData() { 1889 createBasicProfileContact(new ContentValues()); 1890 1891 assertStoredValues(Profile.CONTENT_URI.buildUpon().appendPath("data").build(), 1892 getExpectedProfileDataValues()); 1893 } 1894 1895 public void testQueryProfileEntities() { 1896 createBasicProfileContact(new ContentValues()); 1897 1898 assertStoredValues(Profile.CONTENT_URI.buildUpon().appendPath("entities").build(), 1899 getExpectedProfileDataValues()); 1900 } 1901 1902 public void testQueryRawProfile() { 1903 ContentValues profileValues = new ContentValues(); 1904 createBasicProfileContact(profileValues); 1905 1906 // The raw contact view doesn't include the photo ID. 1907 profileValues.remove(Contacts.PHOTO_ID); 1908 assertStoredValues(Profile.CONTENT_RAW_CONTACTS_URI, profileValues); 1909 } 1910 1911 public void testQueryRawProfileById() { 1912 ContentValues profileValues = new ContentValues(); 1913 long profileRawContactId = createBasicProfileContact(profileValues); 1914 1915 // The raw contact view doesn't include the photo ID. 1916 profileValues.remove(Contacts.PHOTO_ID); 1917 assertStoredValues(ContentUris.withAppendedId( 1918 Profile.CONTENT_RAW_CONTACTS_URI, profileRawContactId), profileValues); 1919 } 1920 1921 public void testQueryRawProfileData() { 1922 long profileRawContactId = createBasicProfileContact(new ContentValues()); 1923 1924 assertStoredValues(ContentUris.withAppendedId( 1925 Profile.CONTENT_RAW_CONTACTS_URI, profileRawContactId).buildUpon() 1926 .appendPath("data").build(), getExpectedProfileDataValues()); 1927 } 1928 1929 public void testQueryRawProfileEntity() { 1930 long profileRawContactId = createBasicProfileContact(new ContentValues()); 1931 1932 assertStoredValues(ContentUris.withAppendedId( 1933 Profile.CONTENT_RAW_CONTACTS_URI, profileRawContactId).buildUpon() 1934 .appendPath("entity").build(), getExpectedProfileDataValues()); 1935 } 1936 1937 public void testQueryDataForProfile() { 1938 createBasicProfileContact(new ContentValues()); 1939 1940 assertStoredValues(Profile.CONTENT_URI.buildUpon().appendPath("data").build(), 1941 getExpectedProfileDataValues()); 1942 } 1943 1944 public void testUpdateProfileRawContact() { 1945 createBasicProfileContact(new ContentValues()); 1946 ContentValues updatedValues = new ContentValues(); 1947 updatedValues.put(RawContacts.SEND_TO_VOICEMAIL, 0); 1948 updatedValues.put(RawContacts.CUSTOM_RINGTONE, "rachmaninoff3"); 1949 updatedValues.put(RawContacts.STARRED, 1); 1950 mResolver.update(Profile.CONTENT_RAW_CONTACTS_URI, updatedValues, null, null); 1951 1952 assertStoredValues(Profile.CONTENT_RAW_CONTACTS_URI, updatedValues); 1953 } 1954 1955 public void testInsertProfileWithDataSetTriggersAccountCreation() { 1956 // Check that we have no profile raw contacts. 1957 assertStoredValues(Profile.CONTENT_RAW_CONTACTS_URI, new ContentValues[]{}); 1958 1959 // Insert a profile record with a new data set. 1960 Account account = new Account("a", "b"); 1961 String dataSet = "c"; 1962 Uri profileUri = maybeAddAccountQueryParameters(Profile.CONTENT_RAW_CONTACTS_URI, account) 1963 .buildUpon().appendQueryParameter(RawContacts.DATA_SET, dataSet).build(); 1964 ContentValues values = new ContentValues(); 1965 long rawContactId = ContentUris.parseId(mResolver.insert(profileUri, values)); 1966 values.put(RawContacts._ID, rawContactId); 1967 1968 // Check that querying for the profile gets the created raw contact. 1969 assertStoredValues(Profile.CONTENT_RAW_CONTACTS_URI, values); 1970 } 1971 1972 public void testPhonesWithStatusUpdate() { 1973 1974 ContentValues values = new ContentValues(); 1975 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1976 long rawContactId = ContentUris.parseId(rawContactUri); 1977 insertStructuredName(rawContactId, "John", "Doe"); 1978 Uri photoUri = insertPhoto(rawContactId); 1979 long photoId = ContentUris.parseId(photoUri); 1980 insertPhoneNumber(rawContactId, "18004664411"); 1981 insertPhoneNumber(rawContactId, "18004664412"); 1982 insertEmail(rawContactId, "goog411@acme.com"); 1983 insertEmail(rawContactId, "goog412@acme.com"); 1984 1985 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog411@acme.com", 1986 StatusUpdates.INVISIBLE, "Bad", 1987 StatusUpdates.CAPABILITY_HAS_CAMERA); 1988 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog412@acme.com", 1989 StatusUpdates.AVAILABLE, "Good", 1990 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VOICE); 1991 long contactId = queryContactId(rawContactId); 1992 1993 Uri uri = Data.CONTENT_URI; 1994 1995 Cursor c = mResolver.query(uri, null, RawContacts.CONTACT_ID + "=" + contactId + " AND " 1996 + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'", null, Phone.NUMBER); 1997 assertEquals(2, c.getCount()); 1998 1999 c.moveToFirst(); 2000 2001 values.clear(); 2002 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 2003 values.put(Contacts.CONTACT_STATUS, "Bad"); 2004 values.put(Contacts.DISPLAY_NAME, "John Doe"); 2005 values.put(Phone.NUMBER, "18004664411"); 2006 values.putNull(Phone.LABEL); 2007 values.put(RawContacts.CONTACT_ID, contactId); 2008 assertCursorValues(c, values); 2009 2010 c.moveToNext(); 2011 2012 values.clear(); 2013 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 2014 values.put(Contacts.CONTACT_STATUS, "Bad"); 2015 values.put(Contacts.DISPLAY_NAME, "John Doe"); 2016 values.put(Phone.NUMBER, "18004664412"); 2017 values.putNull(Phone.LABEL); 2018 values.put(RawContacts.CONTACT_ID, contactId); 2019 assertCursorValues(c, values); 2020 2021 c.close(); 2022 } 2023 2024 public void testGroupQuery() { 2025 Account account1 = new Account("a", "b"); 2026 Account account2 = new Account("c", "d"); 2027 long groupId1 = createGroup(account1, "e", "f"); 2028 long groupId2 = createGroup(account2, "g", "h"); 2029 Uri uri1 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account1); 2030 Uri uri2 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account2); 2031 assertEquals(1, getCount(uri1, null, null)); 2032 assertEquals(1, getCount(uri2, null, null)); 2033 assertStoredValue(uri1, Groups._ID + "=" + groupId1, null, Groups._ID, groupId1) ; 2034 assertStoredValue(uri2, Groups._ID + "=" + groupId2, null, Groups._ID, groupId2) ; 2035 } 2036 2037 public void testGroupInsert() { 2038 ContentValues values = new ContentValues(); 2039 2040 values.put(Groups.ACCOUNT_NAME, "a"); 2041 values.put(Groups.ACCOUNT_TYPE, "b"); 2042 values.put(Groups.SOURCE_ID, "c"); 2043 values.put(Groups.VERSION, 42); 2044 values.put(Groups.GROUP_VISIBLE, 1); 2045 values.put(Groups.TITLE, "d"); 2046 values.put(Groups.TITLE_RES, 1234); 2047 values.put(Groups.NOTES, "e"); 2048 values.put(Groups.RES_PACKAGE, "f"); 2049 values.put(Groups.SYSTEM_ID, "g"); 2050 values.put(Groups.DELETED, 1); 2051 values.put(Groups.SYNC1, "h"); 2052 values.put(Groups.SYNC2, "i"); 2053 values.put(Groups.SYNC3, "j"); 2054 values.put(Groups.SYNC4, "k"); 2055 2056 Uri rowUri = mResolver.insert(Groups.CONTENT_URI, values); 2057 2058 values.put(Groups.DIRTY, 1); 2059 assertStoredValues(rowUri, values); 2060 } 2061 2062 public void testGroupCreationAfterMembershipInsert() { 2063 long rawContactId1 = createRawContact(mAccount); 2064 Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1"); 2065 2066 long groupId = assertSingleGroup(NO_LONG, mAccount, "gsid1", null); 2067 assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri), 2068 rawContactId1, groupId, "gsid1"); 2069 } 2070 2071 public void testGroupReuseAfterMembershipInsert() { 2072 long rawContactId1 = createRawContact(mAccount); 2073 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 2074 Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1"); 2075 2076 assertSingleGroup(groupId1, mAccount, "gsid1", "title1"); 2077 assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri), 2078 rawContactId1, groupId1, "gsid1"); 2079 } 2080 2081 public void testGroupInsertFailureOnGroupIdConflict() { 2082 long rawContactId1 = createRawContact(mAccount); 2083 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 2084 2085 ContentValues values = new ContentValues(); 2086 values.put(GroupMembership.RAW_CONTACT_ID, rawContactId1); 2087 values.put(GroupMembership.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE); 2088 values.put(GroupMembership.GROUP_SOURCE_ID, "gsid1"); 2089 values.put(GroupMembership.GROUP_ROW_ID, groupId1); 2090 try { 2091 mResolver.insert(Data.CONTENT_URI, values); 2092 fail("the insert was expected to fail, but it succeeded"); 2093 } catch (IllegalArgumentException e) { 2094 // this was expected 2095 } 2096 } 2097 2098 public void testGroupSummaryQuery() { 2099 final Account account1 = new Account("accountName1", "accountType1"); 2100 final Account account2 = new Account("accountName2", "accountType2"); 2101 final long groupId1 = createGroup(account1, "sourceId1", "title1"); 2102 final long groupId2 = createGroup(account2, "sourceId2", "title2"); 2103 final long groupId3 = createGroup(account2, "sourceId3", "title3"); 2104 2105 // Prepare raw contact id not used at all, to test group summary uri won't be confused 2106 // with it. 2107 final long rawContactId0 = createRawContactWithName("firstName0", "lastName0"); 2108 2109 final long rawContactId1 = createRawContactWithName("firstName1", "lastName1"); 2110 insertEmail(rawContactId1, "address1@email.com"); 2111 insertGroupMembership(rawContactId1, groupId1); 2112 2113 final long rawContactId2 = createRawContactWithName("firstName2", "lastName2"); 2114 insertEmail(rawContactId2, "address2@email.com"); 2115 insertPhoneNumber(rawContactId2, "222-222-2222"); 2116 insertGroupMembership(rawContactId2, groupId1); 2117 2118 ContentValues v1 = new ContentValues(); 2119 v1.put(Groups._ID, groupId1); 2120 v1.put(Groups.TITLE, "title1"); 2121 v1.put(Groups.SOURCE_ID, "sourceId1"); 2122 v1.put(Groups.ACCOUNT_NAME, account1.name); 2123 v1.put(Groups.ACCOUNT_TYPE, account1.type); 2124 v1.put(Groups.SUMMARY_COUNT, 2); 2125 v1.put(Groups.SUMMARY_WITH_PHONES, 1); 2126 2127 ContentValues v2 = new ContentValues(); 2128 v2.put(Groups._ID, groupId2); 2129 v2.put(Groups.TITLE, "title2"); 2130 v2.put(Groups.SOURCE_ID, "sourceId2"); 2131 v2.put(Groups.ACCOUNT_NAME, account2.name); 2132 v2.put(Groups.ACCOUNT_TYPE, account2.type); 2133 v2.put(Groups.SUMMARY_COUNT, 0); 2134 v2.put(Groups.SUMMARY_WITH_PHONES, 0); 2135 2136 ContentValues v3 = new ContentValues(); 2137 v3.put(Groups._ID, groupId3); 2138 v3.put(Groups.TITLE, "title3"); 2139 v3.put(Groups.SOURCE_ID, "sourceId3"); 2140 v3.put(Groups.ACCOUNT_NAME, account2.name); 2141 v3.put(Groups.ACCOUNT_TYPE, account2.type); 2142 v3.put(Groups.SUMMARY_COUNT, 0); 2143 v3.put(Groups.SUMMARY_WITH_PHONES, 0); 2144 2145 assertStoredValues(Groups.CONTENT_SUMMARY_URI, new ContentValues[] { v1, v2, v3 }); 2146 2147 // Now rawContactId1 has two phone numbers. 2148 insertPhoneNumber(rawContactId1, "111-111-1111"); 2149 insertPhoneNumber(rawContactId1, "111-111-1112"); 2150 // Result should reflect it correctly (don't count phone numbers but raw contacts) 2151 v1.put(Groups.SUMMARY_WITH_PHONES, v1.getAsInteger(Groups.SUMMARY_WITH_PHONES) + 1); 2152 assertStoredValues(Groups.CONTENT_SUMMARY_URI, new ContentValues[] { v1, v2, v3 }); 2153 2154 // Introduce new raw contact, pretending the user added another info. 2155 final long rawContactId3 = createRawContactWithName("firstName3", "lastName3"); 2156 insertEmail(rawContactId3, "address3@email.com"); 2157 insertPhoneNumber(rawContactId3, "333-333-3333"); 2158 insertGroupMembership(rawContactId3, groupId2); 2159 v2.put(Groups.SUMMARY_COUNT, v2.getAsInteger(Groups.SUMMARY_COUNT) + 1); 2160 v2.put(Groups.SUMMARY_WITH_PHONES, v2.getAsInteger(Groups.SUMMARY_WITH_PHONES) + 1); 2161 2162 assertStoredValues(Groups.CONTENT_SUMMARY_URI, new ContentValues[] { v1, v2, v3 }); 2163 2164 final Uri uri = Groups.CONTENT_SUMMARY_URI.buildUpon() 2165 .appendQueryParameter(Groups.PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT, "true") 2166 .build(); 2167 v1.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 1); 2168 v2.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 2); 2169 v3.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 2); 2170 assertStoredValues(uri, new ContentValues[] { v1, v2, v3 }); 2171 2172 // Introduce another group in account1, testing SUMMARY_GROUP_COUNT_PER_ACCOUNT correctly 2173 // reflects the change. 2174 final long groupId4 = createGroup(account1, "sourceId4", "title4"); 2175 v1.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 2176 v1.getAsInteger(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT) + 1); 2177 ContentValues v4 = new ContentValues(); 2178 v4.put(Groups._ID, groupId4); 2179 v4.put(Groups.TITLE, "title4"); 2180 v4.put(Groups.SOURCE_ID, "sourceId4"); 2181 v4.put(Groups.ACCOUNT_NAME, account1.name); 2182 v4.put(Groups.ACCOUNT_TYPE, account1.type); 2183 v4.put(Groups.SUMMARY_COUNT, 0); 2184 v4.put(Groups.SUMMARY_WITH_PHONES, 0); 2185 v4.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 2186 v1.getAsInteger(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT)); 2187 assertStoredValues(uri, new ContentValues[] { v1, v2, v3, v4 }); 2188 } 2189 2190 public void testSettingsQuery() { 2191 Account account1 = new Account("a", "b"); 2192 Account account2 = new Account("c", "d"); 2193 AccountWithDataSet account3 = new AccountWithDataSet("e", "f", "plus"); 2194 createSettings(account1, "0", "0"); 2195 createSettings(account2, "1", "1"); 2196 createSettings(account3, "1", "0"); 2197 Uri uri1 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account1); 2198 Uri uri2 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account2); 2199 Uri uri3 = Settings.CONTENT_URI.buildUpon() 2200 .appendQueryParameter(RawContacts.ACCOUNT_NAME, account3.getAccountName()) 2201 .appendQueryParameter(RawContacts.ACCOUNT_TYPE, account3.getAccountType()) 2202 .appendQueryParameter(RawContacts.DATA_SET, account3.getDataSet()) 2203 .build(); 2204 assertEquals(1, getCount(uri1, null, null)); 2205 assertEquals(1, getCount(uri2, null, null)); 2206 assertEquals(1, getCount(uri3, null, null)); 2207 assertStoredValue(uri1, Settings.SHOULD_SYNC, "0") ; 2208 assertStoredValue(uri1, Settings.UNGROUPED_VISIBLE, "0"); 2209 assertStoredValue(uri2, Settings.SHOULD_SYNC, "1") ; 2210 assertStoredValue(uri2, Settings.UNGROUPED_VISIBLE, "1"); 2211 assertStoredValue(uri3, Settings.SHOULD_SYNC, "1"); 2212 assertStoredValue(uri3, Settings.UNGROUPED_VISIBLE, "0"); 2213 } 2214 2215 public void testSettingsInsertionPreventsDuplicates() { 2216 Account account1 = new Account("a", "b"); 2217 AccountWithDataSet account2 = new AccountWithDataSet("c", "d", "plus"); 2218 createSettings(account1, "0", "0"); 2219 createSettings(account2, "1", "1"); 2220 2221 // Now try creating the settings rows again. It should update the existing settings rows. 2222 createSettings(account1, "1", "0"); 2223 assertStoredValue(Settings.CONTENT_URI, 2224 Settings.ACCOUNT_NAME + "=? AND " + Settings.ACCOUNT_TYPE + "=?", 2225 new String[] {"a", "b"}, Settings.SHOULD_SYNC, "1"); 2226 2227 createSettings(account2, "0", "1"); 2228 assertStoredValue(Settings.CONTENT_URI, 2229 Settings.ACCOUNT_NAME + "=? AND " + Settings.ACCOUNT_TYPE + "=? AND " + 2230 Settings.DATA_SET + "=?", 2231 new String[] {"c", "d", "plus"}, Settings.SHOULD_SYNC, "0"); 2232 } 2233 2234 public void testDisplayNameParsingWhenPartsUnspecified() { 2235 long rawContactId = createRawContact(); 2236 ContentValues values = new ContentValues(); 2237 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 2238 insertStructuredName(rawContactId, values); 2239 2240 assertStructuredName(rawContactId, "Mr.", "John", "Kevin", "von Smith", "Jr."); 2241 } 2242 2243 public void testDisplayNameParsingWhenPartsAreNull() { 2244 long rawContactId = createRawContact(); 2245 ContentValues values = new ContentValues(); 2246 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 2247 values.putNull(StructuredName.GIVEN_NAME); 2248 values.putNull(StructuredName.FAMILY_NAME); 2249 insertStructuredName(rawContactId, values); 2250 assertStructuredName(rawContactId, "Mr.", "John", "Kevin", "von Smith", "Jr."); 2251 } 2252 2253 public void testDisplayNameParsingWhenPartsSpecified() { 2254 long rawContactId = createRawContact(); 2255 ContentValues values = new ContentValues(); 2256 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 2257 values.put(StructuredName.FAMILY_NAME, "Johnson"); 2258 insertStructuredName(rawContactId, values); 2259 2260 assertStructuredName(rawContactId, null, null, null, "Johnson", null); 2261 } 2262 2263 public void testContactWithoutPhoneticName() { 2264 final long rawContactId = createRawContact(null); 2265 2266 ContentValues values = new ContentValues(); 2267 values.put(StructuredName.PREFIX, "Mr"); 2268 values.put(StructuredName.GIVEN_NAME, "John"); 2269 values.put(StructuredName.MIDDLE_NAME, "K."); 2270 values.put(StructuredName.FAMILY_NAME, "Doe"); 2271 values.put(StructuredName.SUFFIX, "Jr."); 2272 Uri dataUri = insertStructuredName(rawContactId, values); 2273 2274 values.clear(); 2275 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 2276 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "Mr John K. Doe, Jr."); 2277 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "Mr Doe, John K., Jr."); 2278 values.putNull(RawContacts.PHONETIC_NAME); 2279 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 2280 values.put(RawContacts.SORT_KEY_PRIMARY, "John K. Doe, Jr."); 2281 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "Doe, John K., Jr."); 2282 2283 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 2284 assertStoredValues(rawContactUri, values); 2285 2286 values.clear(); 2287 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 2288 values.put(Contacts.DISPLAY_NAME_PRIMARY, "Mr John K. Doe, Jr."); 2289 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "Mr Doe, John K., Jr."); 2290 values.putNull(Contacts.PHONETIC_NAME); 2291 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 2292 values.put(Contacts.SORT_KEY_PRIMARY, "John K. Doe, Jr."); 2293 values.put(Contacts.SORT_KEY_ALTERNATIVE, "Doe, John K., Jr."); 2294 2295 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 2296 queryContactId(rawContactId)); 2297 assertStoredValues(contactUri, values); 2298 2299 // The same values should be available through a join with Data 2300 assertStoredValues(dataUri, values); 2301 } 2302 2303 public void testContactWithChineseName() { 2304 2305 // Only run this test when Chinese collation is supported 2306 if (!Arrays.asList(Collator.getAvailableLocales()).contains(Locale.CHINA)) { 2307 return; 2308 } 2309 2310 long rawContactId = createRawContact(null); 2311 2312 ContentValues values = new ContentValues(); 2313 values.put(StructuredName.DISPLAY_NAME, "\u6BB5\u5C0F\u6D9B"); 2314 Uri dataUri = insertStructuredName(rawContactId, values); 2315 2316 values.clear(); 2317 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 2318 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "\u6BB5\u5C0F\u6D9B"); 2319 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B"); 2320 values.putNull(RawContacts.PHONETIC_NAME); 2321 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 2322 values.put(RawContacts.SORT_KEY_PRIMARY, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 2323 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 2324 2325 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 2326 assertStoredValues(rawContactUri, values); 2327 2328 values.clear(); 2329 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 2330 values.put(Contacts.DISPLAY_NAME_PRIMARY, "\u6BB5\u5C0F\u6D9B"); 2331 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B"); 2332 values.putNull(Contacts.PHONETIC_NAME); 2333 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 2334 values.put(Contacts.SORT_KEY_PRIMARY, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 2335 values.put(Contacts.SORT_KEY_ALTERNATIVE, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 2336 2337 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 2338 queryContactId(rawContactId)); 2339 assertStoredValues(contactUri, values); 2340 2341 // The same values should be available through a join with Data 2342 assertStoredValues(dataUri, values); 2343 } 2344 2345 public void testContactWithJapaneseName() { 2346 long rawContactId = createRawContact(null); 2347 2348 ContentValues values = new ContentValues(); 2349 values.put(StructuredName.GIVEN_NAME, "\u7A7A\u6D77"); 2350 values.put(StructuredName.PHONETIC_GIVEN_NAME, "\u304B\u3044\u304F\u3046"); 2351 Uri dataUri = insertStructuredName(rawContactId, values); 2352 2353 values.clear(); 2354 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 2355 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "\u7A7A\u6D77"); 2356 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "\u7A7A\u6D77"); 2357 values.put(RawContacts.PHONETIC_NAME, "\u304B\u3044\u304F\u3046"); 2358 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 2359 values.put(RawContacts.SORT_KEY_PRIMARY, "\u304B\u3044\u304F\u3046"); 2360 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "\u304B\u3044\u304F\u3046"); 2361 2362 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 2363 assertStoredValues(rawContactUri, values); 2364 2365 values.clear(); 2366 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 2367 values.put(Contacts.DISPLAY_NAME_PRIMARY, "\u7A7A\u6D77"); 2368 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "\u7A7A\u6D77"); 2369 values.put(Contacts.PHONETIC_NAME, "\u304B\u3044\u304F\u3046"); 2370 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 2371 values.put(Contacts.SORT_KEY_PRIMARY, "\u304B\u3044\u304F\u3046"); 2372 values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u304B\u3044\u304F\u3046"); 2373 2374 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 2375 queryContactId(rawContactId)); 2376 assertStoredValues(contactUri, values); 2377 2378 // The same values should be available through a join with Data 2379 assertStoredValues(dataUri, values); 2380 } 2381 2382 public void testDisplayNameUpdate() { 2383 long rawContactId1 = createRawContact(); 2384 insertEmail(rawContactId1, "potato@acme.com", true); 2385 2386 long rawContactId2 = createRawContact(); 2387 insertPhoneNumber(rawContactId2, "123456789", true); 2388 2389 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 2390 rawContactId1, rawContactId2); 2391 2392 assertAggregated(rawContactId1, rawContactId2, "123456789"); 2393 2394 insertStructuredName(rawContactId2, "Potato", "Head"); 2395 2396 assertAggregated(rawContactId1, rawContactId2, "Potato Head"); 2397 assertNetworkNotified(true); 2398 } 2399 2400 public void testDisplayNameFromData() { 2401 long rawContactId = createRawContact(); 2402 long contactId = queryContactId(rawContactId); 2403 ContentValues values = new ContentValues(); 2404 2405 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2406 2407 assertStoredValue(uri, Contacts.DISPLAY_NAME, null); 2408 insertEmail(rawContactId, "mike@monstersinc.com"); 2409 assertStoredValue(uri, Contacts.DISPLAY_NAME, "mike@monstersinc.com"); 2410 2411 insertEmail(rawContactId, "james@monstersinc.com", true); 2412 assertStoredValue(uri, Contacts.DISPLAY_NAME, "james@monstersinc.com"); 2413 2414 insertPhoneNumber(rawContactId, "1-800-466-4411"); 2415 assertStoredValue(uri, Contacts.DISPLAY_NAME, "1-800-466-4411"); 2416 2417 // If there are title and company, the company is display name. 2418 values.clear(); 2419 values.put(Organization.COMPANY, "Monsters Inc"); 2420 Uri organizationUri = insertOrganization(rawContactId, values); 2421 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Monsters Inc"); 2422 2423 // If there is nickname, that is display name. 2424 insertNickname(rawContactId, "Sully"); 2425 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Sully"); 2426 2427 // If there is structured name, that is display name. 2428 values.clear(); 2429 values.put(StructuredName.GIVEN_NAME, "James"); 2430 values.put(StructuredName.MIDDLE_NAME, "P."); 2431 values.put(StructuredName.FAMILY_NAME, "Sullivan"); 2432 insertStructuredName(rawContactId, values); 2433 assertStoredValue(uri, Contacts.DISPLAY_NAME, "James P. Sullivan"); 2434 } 2435 2436 public void testDisplayNameFromOrganizationWithoutPhoneticName() { 2437 long rawContactId = createRawContact(); 2438 long contactId = queryContactId(rawContactId); 2439 ContentValues values = new ContentValues(); 2440 2441 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2442 2443 // If there is title without company, the title is display name. 2444 values.clear(); 2445 values.put(Organization.TITLE, "Protagonist"); 2446 Uri organizationUri = insertOrganization(rawContactId, values); 2447 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Protagonist"); 2448 2449 // If there are title and company, the company is display name. 2450 values.clear(); 2451 values.put(Organization.COMPANY, "Monsters Inc"); 2452 mResolver.update(organizationUri, values, null, null); 2453 2454 values.clear(); 2455 values.put(Contacts.DISPLAY_NAME, "Monsters Inc"); 2456 values.putNull(Contacts.PHONETIC_NAME); 2457 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 2458 values.put(Contacts.SORT_KEY_PRIMARY, "Monsters Inc"); 2459 values.put(Contacts.SORT_KEY_ALTERNATIVE, "Monsters Inc"); 2460 assertStoredValues(uri, values); 2461 } 2462 2463 public void testDisplayNameFromOrganizationWithJapanesePhoneticName() { 2464 long rawContactId = createRawContact(); 2465 long contactId = queryContactId(rawContactId); 2466 ContentValues values = new ContentValues(); 2467 2468 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2469 2470 // If there is title without company, the title is display name. 2471 values.clear(); 2472 values.put(Organization.COMPANY, "DoCoMo"); 2473 values.put(Organization.PHONETIC_NAME, "\u30C9\u30B3\u30E2"); 2474 Uri organizationUri = insertOrganization(rawContactId, values); 2475 2476 values.clear(); 2477 values.put(Contacts.DISPLAY_NAME, "DoCoMo"); 2478 values.put(Contacts.PHONETIC_NAME, "\u30C9\u30B3\u30E2"); 2479 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 2480 values.put(Contacts.SORT_KEY_PRIMARY, "\u30C9\u30B3\u30E2"); 2481 values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u30C9\u30B3\u30E2"); 2482 assertStoredValues(uri, values); 2483 } 2484 2485 public void testDisplayNameFromOrganizationWithChineseName() { 2486 boolean hasChineseCollator = false; 2487 final Locale locale[] = Collator.getAvailableLocales(); 2488 for (int i = 0; i < locale.length; i++) { 2489 if (locale[i].equals(Locale.CHINA)) { 2490 hasChineseCollator = true; 2491 break; 2492 } 2493 } 2494 2495 if (!hasChineseCollator) { 2496 return; 2497 } 2498 2499 long rawContactId = createRawContact(); 2500 long contactId = queryContactId(rawContactId); 2501 ContentValues values = new ContentValues(); 2502 2503 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2504 2505 // If there is title without company, the title is display name. 2506 values.clear(); 2507 values.put(Organization.COMPANY, "\u4E2D\u56FD\u7535\u4FE1"); 2508 Uri organizationUri = insertOrganization(rawContactId, values); 2509 2510 values.clear(); 2511 values.put(Contacts.DISPLAY_NAME, "\u4E2D\u56FD\u7535\u4FE1"); 2512 values.putNull(Contacts.PHONETIC_NAME); 2513 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 2514 values.put(Contacts.SORT_KEY_PRIMARY, "ZHONG \u4E2D GUO \u56FD DIAN \u7535 XIN \u4FE1"); 2515 values.put(Contacts.SORT_KEY_ALTERNATIVE, "ZHONG \u4E2D GUO \u56FD DIAN \u7535 XIN \u4FE1"); 2516 assertStoredValues(uri, values); 2517 } 2518 2519 public void testLookupByOrganization() { 2520 long rawContactId = createRawContact(); 2521 long contactId = queryContactId(rawContactId); 2522 ContentValues values = new ContentValues(); 2523 2524 values.clear(); 2525 values.put(Organization.COMPANY, "acmecorp"); 2526 values.put(Organization.TITLE, "president"); 2527 Uri organizationUri = insertOrganization(rawContactId, values); 2528 2529 assertContactFilter(contactId, "acmecorp"); 2530 assertContactFilter(contactId, "president"); 2531 2532 values.clear(); 2533 values.put(Organization.DEPARTMENT, "software"); 2534 mResolver.update(organizationUri, values, null, null); 2535 2536 assertContactFilter(contactId, "acmecorp"); 2537 assertContactFilter(contactId, "president"); 2538 2539 values.clear(); 2540 values.put(Organization.COMPANY, "incredibles"); 2541 mResolver.update(organizationUri, values, null, null); 2542 2543 assertContactFilter(contactId, "incredibles"); 2544 assertContactFilter(contactId, "president"); 2545 2546 values.clear(); 2547 values.put(Organization.TITLE, "director"); 2548 mResolver.update(organizationUri, values, null, null); 2549 2550 assertContactFilter(contactId, "incredibles"); 2551 assertContactFilter(contactId, "director"); 2552 2553 values.clear(); 2554 values.put(Organization.COMPANY, "monsters"); 2555 values.put(Organization.TITLE, "scarer"); 2556 mResolver.update(organizationUri, values, null, null); 2557 2558 assertContactFilter(contactId, "monsters"); 2559 assertContactFilter(contactId, "scarer"); 2560 } 2561 2562 private void assertContactFilter(long contactId, String filter) { 2563 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(filter)); 2564 assertStoredValue(filterUri, Contacts._ID, contactId); 2565 } 2566 2567 private void assertContactFilterNoResult(String filter) { 2568 Uri filterUri4 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, filter); 2569 assertEquals(0, getCount(filterUri4, null, null)); 2570 } 2571 2572 public void testSearchSnippetOrganization() throws Exception { 2573 long rawContactId = createRawContactWithName(); 2574 long contactId = queryContactId(rawContactId); 2575 2576 // Some random data element 2577 insertEmail(rawContactId, "inc@corp.com"); 2578 2579 ContentValues values = new ContentValues(); 2580 values.clear(); 2581 values.put(Organization.COMPANY, "acmecorp"); 2582 values.put(Organization.TITLE, "engineer"); 2583 Uri organizationUri = insertOrganization(rawContactId, values); 2584 2585 // Add another matching organization 2586 values.put(Organization.COMPANY, "acmeinc"); 2587 insertOrganization(rawContactId, values); 2588 2589 // Add another non-matching organization 2590 values.put(Organization.COMPANY, "corpacme"); 2591 insertOrganization(rawContactId, values); 2592 2593 // And another data element 2594 insertEmail(rawContactId, "emca@corp.com", true, Email.TYPE_CUSTOM, "Custom"); 2595 2596 Uri filterUri = buildFilterUri("acme", true); 2597 2598 values.clear(); 2599 values.put(Contacts._ID, contactId); 2600 values.put(SearchSnippetColumns.SNIPPET, "engineer, [acmecorp]"); 2601 assertStoredValues(filterUri, values); 2602 } 2603 2604 public void testSearchSnippetEmail() throws Exception { 2605 long rawContactId = createRawContact(); 2606 long contactId = queryContactId(rawContactId); 2607 ContentValues values = new ContentValues(); 2608 2609 insertStructuredName(rawContactId, "John", "Doe"); 2610 Uri dataUri = insertEmail(rawContactId, "acme@corp.com", true, Email.TYPE_CUSTOM, "Custom"); 2611 2612 Uri filterUri = buildFilterUri("acme", true); 2613 2614 values.clear(); 2615 values.put(Contacts._ID, contactId); 2616 values.put(SearchSnippetColumns.SNIPPET, "[acme@corp.com]"); 2617 assertStoredValues(filterUri, values); 2618 } 2619 2620 public void testSearchSnippetPhone() throws Exception { 2621 long rawContactId = createRawContact(); 2622 long contactId = queryContactId(rawContactId); 2623 ContentValues values = new ContentValues(); 2624 2625 insertStructuredName(rawContactId, "Cave", "Johnson"); 2626 insertPhoneNumber(rawContactId, "(860) 555-1234"); 2627 2628 values.clear(); 2629 values.put(Contacts._ID, contactId); 2630 values.put(SearchSnippetColumns.SNIPPET, "[(860) 555-1234]"); 2631 2632 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 2633 Uri.encode("86 (0) 5-55-12-34")), values); 2634 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 2635 Uri.encode("860 555-1234")), values); 2636 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 2637 Uri.encode("860")), values); 2638 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 2639 Uri.encode("8605551234")), values); 2640 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 2641 Uri.encode("860555")), values); 2642 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 2643 Uri.encode("860 555")), values); 2644 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 2645 Uri.encode("860-555")), values); 2646 } 2647 2648 private Uri buildFilterUri(String query, boolean deferredSnippeting) { 2649 Uri.Builder builder = Contacts.CONTENT_FILTER_URI.buildUpon() 2650 .appendPath(Uri.encode(query)); 2651 if (deferredSnippeting) { 2652 builder.appendQueryParameter(ContactsContract.DEFERRED_SNIPPETING, "1"); 2653 } 2654 return builder.build(); 2655 } 2656 2657 public void testSearchSnippetNickname() throws Exception { 2658 long rawContactId = createRawContactWithName(); 2659 long contactId = queryContactId(rawContactId); 2660 ContentValues values = new ContentValues(); 2661 2662 Uri dataUri = insertNickname(rawContactId, "Incredible"); 2663 2664 Uri filterUri = buildFilterUri("inc", true); 2665 2666 values.clear(); 2667 values.put(Contacts._ID, contactId); 2668 values.put(SearchSnippetColumns.SNIPPET, "[Incredible]"); 2669 assertStoredValues(filterUri, values); 2670 } 2671 2672 public void testSearchSnippetEmptyForNameInDisplayName() throws Exception { 2673 long rawContactId = createRawContact(); 2674 long contactId = queryContactId(rawContactId); 2675 insertStructuredName(rawContactId, "Cave", "Johnson"); 2676 insertEmail(rawContactId, "cave@aperturescience.com", true); 2677 2678 ContentValues emptySnippet = new ContentValues(); 2679 emptySnippet.clear(); 2680 emptySnippet.put(Contacts._ID, contactId); 2681 emptySnippet.put(SearchSnippetColumns.SNIPPET, (String) null); 2682 2683 assertStoredValues(buildFilterUri("cave", true), emptySnippet); 2684 assertStoredValues(buildFilterUri("john", true), emptySnippet); 2685 } 2686 2687 public void testSearchSnippetEmptyForNicknameInDisplayName() throws Exception { 2688 long rawContactId = createRawContact(); 2689 long contactId = queryContactId(rawContactId); 2690 insertNickname(rawContactId, "Caveman"); 2691 insertEmail(rawContactId, "cave@aperturescience.com", true); 2692 2693 ContentValues emptySnippet = new ContentValues(); 2694 emptySnippet.clear(); 2695 emptySnippet.put(Contacts._ID, contactId); 2696 emptySnippet.put(SearchSnippetColumns.SNIPPET, (String) null); 2697 2698 assertStoredValues(buildFilterUri("cave", true), emptySnippet); 2699 } 2700 2701 public void testSearchSnippetEmptyForCompanyInDisplayName() throws Exception { 2702 long rawContactId = createRawContact(); 2703 long contactId = queryContactId(rawContactId); 2704 ContentValues company = new ContentValues(); 2705 company.clear(); 2706 company.put(Organization.COMPANY, "Aperture Science"); 2707 company.put(Organization.TITLE, "President"); 2708 insertOrganization(rawContactId, company); 2709 insertEmail(rawContactId, "aperturepresident@aperturescience.com", true); 2710 2711 ContentValues emptySnippet = new ContentValues(); 2712 emptySnippet.clear(); 2713 emptySnippet.put(Contacts._ID, contactId); 2714 emptySnippet.put(SearchSnippetColumns.SNIPPET, (String) null); 2715 2716 assertStoredValues(buildFilterUri("aperture", true), emptySnippet); 2717 } 2718 2719 public void testSearchSnippetEmptyForPhoneInDisplayName() throws Exception { 2720 long rawContactId = createRawContact(); 2721 long contactId = queryContactId(rawContactId); 2722 insertPhoneNumber(rawContactId, "860-555-1234"); 2723 insertEmail(rawContactId, "860@aperturescience.com", true); 2724 2725 ContentValues emptySnippet = new ContentValues(); 2726 emptySnippet.clear(); 2727 emptySnippet.put(Contacts._ID, contactId); 2728 emptySnippet.put(SearchSnippetColumns.SNIPPET, (String) null); 2729 2730 assertStoredValues(buildFilterUri("860", true), emptySnippet); 2731 } 2732 2733 public void testSearchSnippetEmptyForEmailInDisplayName() throws Exception { 2734 long rawContactId = createRawContact(); 2735 long contactId = queryContactId(rawContactId); 2736 insertEmail(rawContactId, "cave@aperturescience.com", true); 2737 insertNote(rawContactId, "Cave Johnson is president of Aperture Science"); 2738 2739 ContentValues emptySnippet = new ContentValues(); 2740 emptySnippet.clear(); 2741 emptySnippet.put(Contacts._ID, contactId); 2742 emptySnippet.put(SearchSnippetColumns.SNIPPET, (String) null); 2743 2744 assertStoredValues(buildFilterUri("cave", true), emptySnippet); 2745 } 2746 2747 public void testDisplayNameUpdateFromStructuredNameUpdate() { 2748 long rawContactId = createRawContact(); 2749 Uri nameUri = insertStructuredName(rawContactId, "Slinky", "Dog"); 2750 2751 long contactId = queryContactId(rawContactId); 2752 2753 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2754 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky Dog"); 2755 2756 ContentValues values = new ContentValues(); 2757 values.putNull(StructuredName.FAMILY_NAME); 2758 2759 mResolver.update(nameUri, values, null, null); 2760 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky"); 2761 2762 values.putNull(StructuredName.GIVEN_NAME); 2763 2764 mResolver.update(nameUri, values, null, null); 2765 assertStoredValue(uri, Contacts.DISPLAY_NAME, null); 2766 2767 values.put(StructuredName.FAMILY_NAME, "Dog"); 2768 mResolver.update(nameUri, values, null, null); 2769 2770 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Dog"); 2771 } 2772 2773 public void testInsertDataWithContentProviderOperations() throws Exception { 2774 ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 2775 .withValues(new ContentValues()) 2776 .build(); 2777 ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 2778 .withValueBackReference(Data.RAW_CONTACT_ID, 0) 2779 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 2780 .withValue(StructuredName.GIVEN_NAME, "John") 2781 .withValue(StructuredName.FAMILY_NAME, "Doe") 2782 .build(); 2783 ContentProviderResult[] results = 2784 mResolver.applyBatch(ContactsContract.AUTHORITY, Lists.newArrayList(cpo1, cpo2)); 2785 long contactId = queryContactId(ContentUris.parseId(results[0].uri)); 2786 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2787 assertStoredValue(uri, Contacts.DISPLAY_NAME, "John Doe"); 2788 } 2789 2790 public void testSendToVoicemailDefault() { 2791 long rawContactId = createRawContactWithName(); 2792 long contactId = queryContactId(rawContactId); 2793 2794 Cursor c = queryContact(contactId); 2795 assertTrue(c.moveToNext()); 2796 int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL)); 2797 assertEquals(0, sendToVoicemail); 2798 c.close(); 2799 } 2800 2801 public void testSetSendToVoicemailAndRingtone() { 2802 long rawContactId = createRawContactWithName(); 2803 long contactId = queryContactId(rawContactId); 2804 2805 updateSendToVoicemailAndRingtone(contactId, true, "foo"); 2806 assertSendToVoicemailAndRingtone(contactId, true, "foo"); 2807 assertNetworkNotified(false); 2808 2809 updateSendToVoicemailAndRingtoneWithSelection(contactId, false, "bar"); 2810 assertSendToVoicemailAndRingtone(contactId, false, "bar"); 2811 assertNetworkNotified(false); 2812 } 2813 2814 public void testSendToVoicemailAndRingtoneAfterAggregation() { 2815 long rawContactId1 = createRawContactWithName("a", "b"); 2816 long contactId1 = queryContactId(rawContactId1); 2817 updateSendToVoicemailAndRingtone(contactId1, true, "foo"); 2818 2819 long rawContactId2 = createRawContactWithName("c", "d"); 2820 long contactId2 = queryContactId(rawContactId2); 2821 updateSendToVoicemailAndRingtone(contactId2, true, "bar"); 2822 2823 // Aggregate them 2824 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 2825 rawContactId1, rawContactId2); 2826 2827 // Both contacts had "send to VM", the contact now has the same value 2828 assertSendToVoicemailAndRingtone(contactId1, true, "foo,bar"); // Either foo or bar 2829 } 2830 2831 public void testDoNotSendToVoicemailAfterAggregation() { 2832 long rawContactId1 = createRawContactWithName("e", "f"); 2833 long contactId1 = queryContactId(rawContactId1); 2834 updateSendToVoicemailAndRingtone(contactId1, true, null); 2835 2836 long rawContactId2 = createRawContactWithName("g", "h"); 2837 long contactId2 = queryContactId(rawContactId2); 2838 updateSendToVoicemailAndRingtone(contactId2, false, null); 2839 2840 // Aggregate them 2841 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 2842 rawContactId1, rawContactId2); 2843 2844 // Since one of the contacts had "don't send to VM" that setting wins for the aggregate 2845 assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), false, null); 2846 } 2847 2848 public void testSetSendToVoicemailAndRingtonePreservedAfterJoinAndSplit() { 2849 long rawContactId1 = createRawContactWithName("i", "j"); 2850 long contactId1 = queryContactId(rawContactId1); 2851 updateSendToVoicemailAndRingtone(contactId1, true, "foo"); 2852 2853 long rawContactId2 = createRawContactWithName("k", "l"); 2854 long contactId2 = queryContactId(rawContactId2); 2855 updateSendToVoicemailAndRingtone(contactId2, false, "bar"); 2856 2857 // Aggregate them 2858 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 2859 rawContactId1, rawContactId2); 2860 2861 // Split them 2862 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 2863 rawContactId1, rawContactId2); 2864 2865 assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), true, "foo"); 2866 assertSendToVoicemailAndRingtone(queryContactId(rawContactId2), false, "bar"); 2867 } 2868 2869 public void testStatusUpdateInsert() { 2870 long rawContactId = createRawContact(); 2871 Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 2872 long dataId = ContentUris.parseId(imUri); 2873 2874 ContentValues values = new ContentValues(); 2875 values.put(StatusUpdates.DATA_ID, dataId); 2876 values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM); 2877 values.putNull(StatusUpdates.CUSTOM_PROTOCOL); 2878 values.put(StatusUpdates.IM_HANDLE, "aim"); 2879 values.put(StatusUpdates.PRESENCE, StatusUpdates.INVISIBLE); 2880 values.put(StatusUpdates.STATUS, "Hiding"); 2881 values.put(StatusUpdates.STATUS_TIMESTAMP, 100); 2882 values.put(StatusUpdates.STATUS_RES_PACKAGE, "a.b.c"); 2883 values.put(StatusUpdates.STATUS_ICON, 1234); 2884 values.put(StatusUpdates.STATUS_LABEL, 2345); 2885 2886 Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values); 2887 2888 assertStoredValues(resultUri, values); 2889 2890 long contactId = queryContactId(rawContactId); 2891 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2892 2893 values.clear(); 2894 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 2895 values.put(Contacts.CONTACT_STATUS, "Hiding"); 2896 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100); 2897 values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "a.b.c"); 2898 values.put(Contacts.CONTACT_STATUS_ICON, 1234); 2899 values.put(Contacts.CONTACT_STATUS_LABEL, 2345); 2900 2901 assertStoredValues(contactUri, values); 2902 2903 values.clear(); 2904 values.put(StatusUpdates.DATA_ID, dataId); 2905 values.put(StatusUpdates.STATUS, "Cloaked"); 2906 values.put(StatusUpdates.STATUS_TIMESTAMP, 200); 2907 values.put(StatusUpdates.STATUS_RES_PACKAGE, "d.e.f"); 2908 values.put(StatusUpdates.STATUS_ICON, 4321); 2909 values.put(StatusUpdates.STATUS_LABEL, 5432); 2910 mResolver.insert(StatusUpdates.CONTENT_URI, values); 2911 2912 values.clear(); 2913 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 2914 values.put(Contacts.CONTACT_STATUS, "Cloaked"); 2915 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 200); 2916 values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "d.e.f"); 2917 values.put(Contacts.CONTACT_STATUS_ICON, 4321); 2918 values.put(Contacts.CONTACT_STATUS_LABEL, 5432); 2919 assertStoredValues(contactUri, values); 2920 } 2921 2922 public void testStatusUpdateInferAttribution() { 2923 long rawContactId = createRawContact(); 2924 Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 2925 long dataId = ContentUris.parseId(imUri); 2926 2927 ContentValues values = new ContentValues(); 2928 values.put(StatusUpdates.DATA_ID, dataId); 2929 values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM); 2930 values.put(StatusUpdates.IM_HANDLE, "aim"); 2931 values.put(StatusUpdates.STATUS, "Hiding"); 2932 2933 Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values); 2934 2935 values.clear(); 2936 values.put(StatusUpdates.DATA_ID, dataId); 2937 values.put(StatusUpdates.STATUS_LABEL, com.android.internal.R.string.imProtocolAim); 2938 values.put(StatusUpdates.STATUS, "Hiding"); 2939 2940 assertStoredValues(resultUri, values); 2941 } 2942 2943 public void testStatusUpdateMatchingImOrEmail() { 2944 long rawContactId = createRawContact(); 2945 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 2946 insertImHandle(rawContactId, Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im"); 2947 insertEmail(rawContactId, "m@acme.com"); 2948 2949 // Match on IM (standard) 2950 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available", 2951 StatusUpdates.CAPABILITY_HAS_CAMERA); 2952 2953 // Match on IM (custom) 2954 insertStatusUpdate(Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im", StatusUpdates.IDLE, "Idle", 2955 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO); 2956 2957 // Match on Email 2958 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "m@acme.com", StatusUpdates.AWAY, "Away", 2959 StatusUpdates.CAPABILITY_HAS_VOICE); 2960 2961 // No match 2962 insertStatusUpdate(Im.PROTOCOL_ICQ, null, "12345", StatusUpdates.DO_NOT_DISTURB, "Go away", 2963 StatusUpdates.CAPABILITY_HAS_CAMERA); 2964 2965 Cursor c = mResolver.query(StatusUpdates.CONTENT_URI, new String[] { 2966 StatusUpdates.DATA_ID, StatusUpdates.PROTOCOL, StatusUpdates.CUSTOM_PROTOCOL, 2967 StatusUpdates.PRESENCE, StatusUpdates.STATUS}, 2968 PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null, StatusUpdates.DATA_ID); 2969 assertTrue(c.moveToNext()); 2970 assertStatusUpdate(c, Im.PROTOCOL_AIM, null, StatusUpdates.AVAILABLE, "Available"); 2971 assertTrue(c.moveToNext()); 2972 assertStatusUpdate(c, Im.PROTOCOL_CUSTOM, "my_im_proto", StatusUpdates.IDLE, "Idle"); 2973 assertTrue(c.moveToNext()); 2974 assertStatusUpdate(c, Im.PROTOCOL_GOOGLE_TALK, null, StatusUpdates.AWAY, "Away"); 2975 assertFalse(c.moveToNext()); 2976 c.close(); 2977 2978 long contactId = queryContactId(rawContactId); 2979 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2980 2981 ContentValues values = new ContentValues(); 2982 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 2983 values.put(Contacts.CONTACT_STATUS, "Available"); 2984 assertStoredValuesWithProjection(contactUri, values); 2985 } 2986 2987 public void testStatusUpdateUpdateAndDelete() { 2988 long rawContactId = createRawContact(); 2989 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 2990 2991 long contactId = queryContactId(rawContactId); 2992 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2993 2994 ContentValues values = new ContentValues(); 2995 values.putNull(Contacts.CONTACT_PRESENCE); 2996 values.putNull(Contacts.CONTACT_STATUS); 2997 assertStoredValuesWithProjection(contactUri, values); 2998 2999 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AWAY, "BUSY", 3000 StatusUpdates.CAPABILITY_HAS_CAMERA); 3001 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.DO_NOT_DISTURB, "GO AWAY", 3002 StatusUpdates.CAPABILITY_HAS_CAMERA); 3003 Uri statusUri = 3004 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available", 3005 StatusUpdates.CAPABILITY_HAS_CAMERA); 3006 long statusId = ContentUris.parseId(statusUri); 3007 3008 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 3009 values.put(Contacts.CONTACT_STATUS, "Available"); 3010 assertStoredValuesWithProjection(contactUri, values); 3011 3012 // update status_updates table to set new values for 3013 // status_updates.status 3014 // status_updates.status_ts 3015 // presence 3016 long updatedTs = 200; 3017 String testUpdate = "test_update"; 3018 String selection = StatusUpdates.DATA_ID + "=" + statusId; 3019 values.clear(); 3020 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 3021 values.put(StatusUpdates.STATUS, testUpdate); 3022 values.put(StatusUpdates.PRESENCE, "presence_test"); 3023 mResolver.update(StatusUpdates.CONTENT_URI, values, 3024 StatusUpdates.DATA_ID + "=" + statusId, null); 3025 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 3026 3027 // update status_updates table to set new values for columns in status_updates table ONLY 3028 // i.e., no rows in presence table are to be updated. 3029 updatedTs = 300; 3030 testUpdate = "test_update_new"; 3031 selection = StatusUpdates.DATA_ID + "=" + statusId; 3032 values.clear(); 3033 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 3034 values.put(StatusUpdates.STATUS, testUpdate); 3035 mResolver.update(StatusUpdates.CONTENT_URI, values, 3036 StatusUpdates.DATA_ID + "=" + statusId, null); 3037 // make sure the presence column value is still the old value 3038 values.put(StatusUpdates.PRESENCE, "presence_test"); 3039 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 3040 3041 // update status_updates table to set new values for columns in presence table ONLY 3042 // i.e., no rows in status_updates table are to be updated. 3043 selection = StatusUpdates.DATA_ID + "=" + statusId; 3044 values.clear(); 3045 values.put(StatusUpdates.PRESENCE, "presence_test_new"); 3046 mResolver.update(StatusUpdates.CONTENT_URI, values, 3047 StatusUpdates.DATA_ID + "=" + statusId, null); 3048 // make sure the status_updates table is not updated 3049 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 3050 values.put(StatusUpdates.STATUS, testUpdate); 3051 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 3052 3053 // effect "delete status_updates" operation and expect the following 3054 // data deleted from status_updates table 3055 // presence set to null 3056 mResolver.delete(StatusUpdates.CONTENT_URI, StatusUpdates.DATA_ID + "=" + statusId, null); 3057 values.clear(); 3058 values.putNull(Contacts.CONTACT_PRESENCE); 3059 assertStoredValuesWithProjection(contactUri, values); 3060 } 3061 3062 public void testStatusUpdateUpdateToNull() { 3063 long rawContactId = createRawContact(); 3064 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 3065 3066 long contactId = queryContactId(rawContactId); 3067 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 3068 3069 ContentValues values = new ContentValues(); 3070 Uri statusUri = 3071 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available", 3072 StatusUpdates.CAPABILITY_HAS_CAMERA); 3073 long statusId = ContentUris.parseId(statusUri); 3074 3075 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 3076 values.put(Contacts.CONTACT_STATUS, "Available"); 3077 assertStoredValuesWithProjection(contactUri, values); 3078 3079 values.clear(); 3080 values.putNull(StatusUpdates.PRESENCE); 3081 mResolver.update(StatusUpdates.CONTENT_URI, values, 3082 StatusUpdates.DATA_ID + "=" + statusId, null); 3083 3084 values.clear(); 3085 values.putNull(Contacts.CONTACT_PRESENCE); 3086 values.put(Contacts.CONTACT_STATUS, "Available"); 3087 assertStoredValuesWithProjection(contactUri, values); 3088 } 3089 3090 public void testStatusUpdateWithTimestamp() { 3091 long rawContactId = createRawContact(); 3092 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 3093 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk"); 3094 3095 long contactId = queryContactId(rawContactId); 3096 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 3097 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Offline", 80, 3098 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 3099 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Available", 100, 3100 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 3101 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", 0, "Busy", 90, 3102 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 3103 3104 // Should return the latest status 3105 ContentValues values = new ContentValues(); 3106 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100); 3107 values.put(Contacts.CONTACT_STATUS, "Available"); 3108 assertStoredValuesWithProjection(contactUri, values); 3109 } 3110 3111 private void assertStatusUpdate(Cursor c, int protocol, String customProtocol, int presence, 3112 String status) { 3113 ContentValues values = new ContentValues(); 3114 values.put(StatusUpdates.PROTOCOL, protocol); 3115 values.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 3116 values.put(StatusUpdates.PRESENCE, presence); 3117 values.put(StatusUpdates.STATUS, status); 3118 assertCursorValues(c, values); 3119 } 3120 3121 // Stream item query test cases. 3122 3123 public void testQueryStreamItemsByRawContactId() { 3124 long rawContactId = createRawContact(mAccount); 3125 ContentValues values = buildGenericStreamItemValues(); 3126 insertStreamItem(rawContactId, values, mAccount); 3127 assertStoredValues( 3128 Uri.withAppendedPath( 3129 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3130 RawContacts.StreamItems.CONTENT_DIRECTORY), 3131 values); 3132 } 3133 3134 public void testQueryStreamItemsByContactId() { 3135 long rawContactId = createRawContact(); 3136 long contactId = queryContactId(rawContactId); 3137 ContentValues values = buildGenericStreamItemValues(); 3138 insertStreamItem(rawContactId, values, null); 3139 assertStoredValues( 3140 Uri.withAppendedPath( 3141 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 3142 Contacts.StreamItems.CONTENT_DIRECTORY), 3143 values); 3144 } 3145 3146 public void testQueryStreamItemsByLookupKey() { 3147 long rawContactId = createRawContact(); 3148 long contactId = queryContactId(rawContactId); 3149 String lookupKey = queryLookupKey(contactId); 3150 ContentValues values = buildGenericStreamItemValues(); 3151 insertStreamItem(rawContactId, values, null); 3152 assertStoredValues( 3153 Uri.withAppendedPath( 3154 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), 3155 Contacts.StreamItems.CONTENT_DIRECTORY), 3156 values); 3157 } 3158 3159 public void testQueryStreamItemsByLookupKeyAndContactId() { 3160 long rawContactId = createRawContact(); 3161 long contactId = queryContactId(rawContactId); 3162 String lookupKey = queryLookupKey(contactId); 3163 ContentValues values = buildGenericStreamItemValues(); 3164 insertStreamItem(rawContactId, values, null); 3165 assertStoredValues( 3166 Uri.withAppendedPath( 3167 ContentUris.withAppendedId( 3168 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), 3169 contactId), 3170 Contacts.StreamItems.CONTENT_DIRECTORY), 3171 values); 3172 } 3173 3174 public void testQueryStreamItems() { 3175 long rawContactId = createRawContact(); 3176 ContentValues values = buildGenericStreamItemValues(); 3177 insertStreamItem(rawContactId, values, null); 3178 assertStoredValues(StreamItems.CONTENT_URI, values); 3179 } 3180 3181 public void testQueryStreamItemsWithSelection() { 3182 long rawContactId = createRawContact(); 3183 ContentValues firstValues = buildGenericStreamItemValues(); 3184 insertStreamItem(rawContactId, firstValues, null); 3185 3186 ContentValues secondValues = buildGenericStreamItemValues(); 3187 secondValues.put(StreamItems.TEXT, "Goodbye world"); 3188 insertStreamItem(rawContactId, secondValues, null); 3189 3190 // Select only the first stream item. 3191 assertStoredValues(StreamItems.CONTENT_URI, StreamItems.TEXT + "=?", 3192 new String[]{"Hello world"}, firstValues); 3193 3194 // Select only the second stream item. 3195 assertStoredValues(StreamItems.CONTENT_URI, StreamItems.TEXT + "=?", 3196 new String[]{"Goodbye world"}, secondValues); 3197 } 3198 3199 public void testQueryStreamItemById() { 3200 long rawContactId = createRawContact(); 3201 ContentValues firstValues = buildGenericStreamItemValues(); 3202 Uri resultUri = insertStreamItem(rawContactId, firstValues, null); 3203 long firstStreamItemId = ContentUris.parseId(resultUri); 3204 3205 ContentValues secondValues = buildGenericStreamItemValues(); 3206 secondValues.put(StreamItems.TEXT, "Goodbye world"); 3207 resultUri = insertStreamItem(rawContactId, secondValues, null); 3208 long secondStreamItemId = ContentUris.parseId(resultUri); 3209 3210 // Select only the first stream item. 3211 assertStoredValues(ContentUris.withAppendedId(StreamItems.CONTENT_URI, firstStreamItemId), 3212 firstValues); 3213 3214 // Select only the second stream item. 3215 assertStoredValues(ContentUris.withAppendedId(StreamItems.CONTENT_URI, secondStreamItemId), 3216 secondValues); 3217 } 3218 3219 // Stream item photo insertion + query test cases. 3220 3221 public void testQueryStreamItemPhotoWithSelection() { 3222 long rawContactId = createRawContact(); 3223 ContentValues values = buildGenericStreamItemValues(); 3224 Uri resultUri = insertStreamItem(rawContactId, values, null); 3225 long streamItemId = ContentUris.parseId(resultUri); 3226 3227 ContentValues photo1Values = buildGenericStreamItemPhotoValues(1); 3228 insertStreamItemPhoto(streamItemId, photo1Values, null); 3229 photo1Values.remove(StreamItemPhotos.PHOTO); // Removed during processing. 3230 ContentValues photo2Values = buildGenericStreamItemPhotoValues(2); 3231 insertStreamItemPhoto(streamItemId, photo2Values, null); 3232 3233 // Select only the first photo. 3234 assertStoredValues(StreamItems.CONTENT_PHOTO_URI, StreamItemPhotos.SORT_INDEX + "=?", 3235 new String[]{"1"}, photo1Values); 3236 } 3237 3238 public void testQueryStreamItemPhotoByStreamItemId() { 3239 long rawContactId = createRawContact(); 3240 3241 // Insert a first stream item. 3242 ContentValues firstValues = buildGenericStreamItemValues(); 3243 Uri resultUri = insertStreamItem(rawContactId, firstValues, null); 3244 long firstStreamItemId = ContentUris.parseId(resultUri); 3245 3246 // Insert a second stream item. 3247 ContentValues secondValues = buildGenericStreamItemValues(); 3248 resultUri = insertStreamItem(rawContactId, secondValues, null); 3249 long secondStreamItemId = ContentUris.parseId(resultUri); 3250 3251 // Add a photo to the first stream item. 3252 ContentValues photo1Values = buildGenericStreamItemPhotoValues(1); 3253 insertStreamItemPhoto(firstStreamItemId, photo1Values, null); 3254 photo1Values.remove(StreamItemPhotos.PHOTO); // Removed during processing. 3255 3256 // Add a photo to the second stream item. 3257 ContentValues photo2Values = buildGenericStreamItemPhotoValues(1); 3258 photo2Values.put(StreamItemPhotos.PHOTO, loadPhotoFromResource( 3259 R.drawable.nebula, PhotoSize.ORIGINAL)); 3260 insertStreamItemPhoto(secondStreamItemId, photo2Values, null); 3261 photo2Values.remove(StreamItemPhotos.PHOTO); // Removed during processing. 3262 3263 // Select only the photos from the second stream item. 3264 assertStoredValues(Uri.withAppendedPath( 3265 ContentUris.withAppendedId(StreamItems.CONTENT_URI, secondStreamItemId), 3266 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), photo2Values); 3267 } 3268 3269 public void testQueryStreamItemPhotoByStreamItemPhotoId() { 3270 long rawContactId = createRawContact(); 3271 3272 // Insert a first stream item. 3273 ContentValues firstValues = buildGenericStreamItemValues(); 3274 Uri resultUri = insertStreamItem(rawContactId, firstValues, null); 3275 long firstStreamItemId = ContentUris.parseId(resultUri); 3276 3277 // Insert a second stream item. 3278 ContentValues secondValues = buildGenericStreamItemValues(); 3279 resultUri = insertStreamItem(rawContactId, secondValues, null); 3280 long secondStreamItemId = ContentUris.parseId(resultUri); 3281 3282 // Add a photo to the first stream item. 3283 ContentValues photo1Values = buildGenericStreamItemPhotoValues(1); 3284 resultUri = insertStreamItemPhoto(firstStreamItemId, photo1Values, null); 3285 long firstPhotoId = ContentUris.parseId(resultUri); 3286 photo1Values.remove(StreamItemPhotos.PHOTO); // Removed during processing. 3287 3288 // Add a photo to the second stream item. 3289 ContentValues photo2Values = buildGenericStreamItemPhotoValues(1); 3290 photo2Values.put(StreamItemPhotos.PHOTO, loadPhotoFromResource( 3291 R.drawable.galaxy, PhotoSize.ORIGINAL)); 3292 resultUri = insertStreamItemPhoto(secondStreamItemId, photo2Values, null); 3293 long secondPhotoId = ContentUris.parseId(resultUri); 3294 photo2Values.remove(StreamItemPhotos.PHOTO); // Removed during processing. 3295 3296 // Select the first photo. 3297 assertStoredValues(ContentUris.withAppendedId( 3298 Uri.withAppendedPath( 3299 ContentUris.withAppendedId(StreamItems.CONTENT_URI, firstStreamItemId), 3300 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 3301 firstPhotoId), 3302 photo1Values); 3303 3304 // Select the second photo. 3305 assertStoredValues(ContentUris.withAppendedId( 3306 Uri.withAppendedPath( 3307 ContentUris.withAppendedId(StreamItems.CONTENT_URI, secondStreamItemId), 3308 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 3309 secondPhotoId), 3310 photo2Values); 3311 } 3312 3313 // Stream item insertion test cases. 3314 3315 public void testInsertStreamItemIntoOtherAccount() { 3316 long rawContactId = createRawContact(mAccount); 3317 ContentValues values = buildGenericStreamItemValues(); 3318 try { 3319 insertStreamItem(rawContactId, values, mAccountTwo); 3320 fail("Stream insertion was allowed in another account's raw contact."); 3321 } catch (SecurityException expected) { 3322 // Trying to insert stream items into account one's raw contact is forbidden. 3323 } 3324 } 3325 3326 public void testInsertStreamItemInProfileRequiresWriteProfileAccess() { 3327 long profileRawContactId = createBasicProfileContact(new ContentValues()); 3328 3329 // With our (default) write profile permission, we should be able to insert a stream item. 3330 ContentValues values = buildGenericStreamItemValues(); 3331 insertStreamItem(profileRawContactId, values, null); 3332 3333 // Now take away write profile permission. 3334 mActor.removePermissions("android.permission.WRITE_PROFILE"); 3335 3336 // Try inserting another stream item. 3337 try { 3338 insertStreamItem(profileRawContactId, values, null); 3339 fail("Should require WRITE_PROFILE access to insert a stream item in the profile."); 3340 } catch (SecurityException expected) { 3341 // Trying to insert a stream item in the profile without WRITE_PROFILE permission 3342 // should fail. 3343 } 3344 } 3345 3346 public void testInsertStreamItemWithContentValues() { 3347 long rawContactId = createRawContact(); 3348 ContentValues values = buildGenericStreamItemValues(); 3349 values.put(StreamItems.RAW_CONTACT_ID, rawContactId); 3350 mResolver.insert(StreamItems.CONTENT_URI, values); 3351 assertStoredValues(Uri.withAppendedPath( 3352 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3353 RawContacts.StreamItems.CONTENT_DIRECTORY), values); 3354 } 3355 3356 public void testInsertStreamItemOverLimit() { 3357 long rawContactId = createRawContact(); 3358 ContentValues values = buildGenericStreamItemValues(); 3359 values.put(StreamItems.RAW_CONTACT_ID, rawContactId); 3360 3361 List<Long> streamItemIds = Lists.newArrayList(); 3362 3363 // Insert MAX + 1 stream items. 3364 long baseTime = System.currentTimeMillis(); 3365 for (int i = 0; i < 6; i++) { 3366 values.put(StreamItems.TIMESTAMP, baseTime + i); 3367 Uri resultUri = mResolver.insert(StreamItems.CONTENT_URI, values); 3368 streamItemIds.add(ContentUris.parseId(resultUri)); 3369 } 3370 Long doomedStreamItemId = streamItemIds.get(0); 3371 3372 // There should only be MAX items. The oldest one should have been cleaned up. 3373 Cursor c = mResolver.query( 3374 Uri.withAppendedPath( 3375 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3376 RawContacts.StreamItems.CONTENT_DIRECTORY), 3377 new String[]{StreamItems._ID}, null, null, null); 3378 try { 3379 while(c.moveToNext()) { 3380 long streamItemId = c.getLong(0); 3381 streamItemIds.remove(streamItemId); 3382 } 3383 } finally { 3384 c.close(); 3385 } 3386 3387 assertEquals(1, streamItemIds.size()); 3388 assertEquals(doomedStreamItemId, streamItemIds.get(0)); 3389 } 3390 3391 public void testInsertStreamItemOlderThanOldestInLimit() { 3392 long rawContactId = createRawContact(); 3393 ContentValues values = buildGenericStreamItemValues(); 3394 values.put(StreamItems.RAW_CONTACT_ID, rawContactId); 3395 3396 // Insert MAX stream items. 3397 long baseTime = System.currentTimeMillis(); 3398 for (int i = 0; i < 5; i++) { 3399 values.put(StreamItems.TIMESTAMP, baseTime + i); 3400 Uri resultUri = mResolver.insert(StreamItems.CONTENT_URI, values); 3401 assertNotSame("Expected non-0 stream item ID to be inserted", 3402 0L, ContentUris.parseId(resultUri)); 3403 } 3404 3405 // Now try to insert a stream item that's older. It should be deleted immediately 3406 // and return an ID of 0. 3407 values.put(StreamItems.TIMESTAMP, baseTime - 1); 3408 Uri resultUri = mResolver.insert(StreamItems.CONTENT_URI, values); 3409 assertEquals(0L, ContentUris.parseId(resultUri)); 3410 } 3411 3412 // Stream item photo insertion test cases. 3413 3414 public void testInsertStreamItemsAndPhotosInBatch() throws Exception { 3415 long rawContactId = createRawContact(); 3416 ContentValues streamItemValues = buildGenericStreamItemValues(); 3417 ContentValues streamItemPhotoValues = buildGenericStreamItemPhotoValues(0); 3418 3419 ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 3420 ops.add(ContentProviderOperation.newInsert( 3421 Uri.withAppendedPath( 3422 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3423 RawContacts.StreamItems.CONTENT_DIRECTORY)) 3424 .withValues(streamItemValues).build()); 3425 for (int i = 0; i < 5; i++) { 3426 streamItemPhotoValues.put(StreamItemPhotos.SORT_INDEX, i); 3427 ops.add(ContentProviderOperation.newInsert(StreamItems.CONTENT_PHOTO_URI) 3428 .withValues(streamItemPhotoValues) 3429 .withValueBackReference(StreamItemPhotos.STREAM_ITEM_ID, 0) 3430 .build()); 3431 } 3432 mResolver.applyBatch(ContactsContract.AUTHORITY, ops); 3433 3434 // Check that all five photos were inserted under the raw contact. 3435 Cursor c = mResolver.query(StreamItems.CONTENT_URI, new String[]{StreamItems._ID}, 3436 StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 3437 null); 3438 long streamItemId = 0; 3439 try { 3440 assertEquals(1, c.getCount()); 3441 c.moveToFirst(); 3442 streamItemId = c.getLong(0); 3443 } finally { 3444 c.close(); 3445 } 3446 3447 c = mResolver.query(Uri.withAppendedPath( 3448 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 3449 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 3450 new String[]{StreamItemPhotos._ID, StreamItemPhotos.PHOTO_URI}, 3451 null, null, null); 3452 try { 3453 assertEquals(5, c.getCount()); 3454 byte[] expectedPhotoBytes = loadPhotoFromResource( 3455 R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO); 3456 while (c.moveToNext()) { 3457 String photoUri = c.getString(1); 3458 assertInputStreamContent(expectedPhotoBytes, 3459 mResolver.openInputStream(Uri.parse(photoUri))); 3460 } 3461 } finally { 3462 c.close(); 3463 } 3464 } 3465 3466 // Stream item update test cases. 3467 3468 public void testUpdateStreamItemById() { 3469 long rawContactId = createRawContact(); 3470 ContentValues values = buildGenericStreamItemValues(); 3471 Uri resultUri = insertStreamItem(rawContactId, values, null); 3472 long streamItemId = ContentUris.parseId(resultUri); 3473 values.put(StreamItems.TEXT, "Goodbye world"); 3474 mResolver.update(ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), values, 3475 null, null); 3476 assertStoredValues(Uri.withAppendedPath( 3477 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3478 RawContacts.StreamItems.CONTENT_DIRECTORY), values); 3479 } 3480 3481 public void testUpdateStreamItemWithContentValues() { 3482 long rawContactId = createRawContact(); 3483 ContentValues values = buildGenericStreamItemValues(); 3484 Uri resultUri = insertStreamItem(rawContactId, values, null); 3485 long streamItemId = ContentUris.parseId(resultUri); 3486 values.put(StreamItems._ID, streamItemId); 3487 values.put(StreamItems.TEXT, "Goodbye world"); 3488 mResolver.update(StreamItems.CONTENT_URI, values, null, null); 3489 assertStoredValues(Uri.withAppendedPath( 3490 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3491 RawContacts.StreamItems.CONTENT_DIRECTORY), values); 3492 } 3493 3494 public void testUpdateStreamItemFromOtherAccount() { 3495 long rawContactId = createRawContact(mAccount); 3496 ContentValues values = buildGenericStreamItemValues(); 3497 Uri resultUri = insertStreamItem(rawContactId, values, mAccount); 3498 long streamItemId = ContentUris.parseId(resultUri); 3499 values.put(StreamItems._ID, streamItemId); 3500 values.put(StreamItems.TEXT, "Goodbye world"); 3501 try { 3502 mResolver.update(maybeAddAccountQueryParameters(StreamItems.CONTENT_URI, mAccountTwo), 3503 values, null, null); 3504 fail("Should not be able to update stream items inserted by another account"); 3505 } catch (SecurityException expected) { 3506 // Can't update the stream items from another account. 3507 } 3508 } 3509 3510 // Stream item photo update test cases. 3511 3512 public void testUpdateStreamItemPhotoById() throws IOException { 3513 long rawContactId = createRawContact(); 3514 ContentValues values = buildGenericStreamItemValues(); 3515 Uri resultUri = insertStreamItem(rawContactId, values, null); 3516 long streamItemId = ContentUris.parseId(resultUri); 3517 ContentValues photoValues = buildGenericStreamItemPhotoValues(1); 3518 resultUri = insertStreamItemPhoto(streamItemId, photoValues, null); 3519 long streamItemPhotoId = ContentUris.parseId(resultUri); 3520 3521 photoValues.put(StreamItemPhotos.PHOTO, loadPhotoFromResource( 3522 R.drawable.nebula, PhotoSize.ORIGINAL)); 3523 Uri photoUri = 3524 ContentUris.withAppendedId( 3525 Uri.withAppendedPath( 3526 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 3527 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 3528 streamItemPhotoId); 3529 mResolver.update(photoUri, photoValues, null, null); 3530 photoValues.remove(StreamItemPhotos.PHOTO); // Removed during processing. 3531 assertStoredValues(photoUri, photoValues); 3532 3533 // Check that the photo stored is the expected one. 3534 String displayPhotoUri = getStoredValue(photoUri, StreamItemPhotos.PHOTO_URI); 3535 assertInputStreamContent(loadPhotoFromResource(R.drawable.nebula, PhotoSize.DISPLAY_PHOTO), 3536 mResolver.openInputStream(Uri.parse(displayPhotoUri))); 3537 } 3538 3539 public void testUpdateStreamItemPhotoWithContentValues() throws IOException { 3540 long rawContactId = createRawContact(); 3541 ContentValues values = buildGenericStreamItemValues(); 3542 Uri resultUri = insertStreamItem(rawContactId, values, null); 3543 long streamItemId = ContentUris.parseId(resultUri); 3544 ContentValues photoValues = buildGenericStreamItemPhotoValues(1); 3545 resultUri = insertStreamItemPhoto(streamItemId, photoValues, null); 3546 long streamItemPhotoId = ContentUris.parseId(resultUri); 3547 3548 photoValues.put(StreamItemPhotos._ID, streamItemPhotoId); 3549 photoValues.put(StreamItemPhotos.PHOTO, loadPhotoFromResource( 3550 R.drawable.nebula, PhotoSize.ORIGINAL)); 3551 Uri photoUri = 3552 Uri.withAppendedPath( 3553 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 3554 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY); 3555 mResolver.update(photoUri, photoValues, null, null); 3556 photoValues.remove(StreamItemPhotos.PHOTO); // Removed during processing. 3557 assertStoredValues(photoUri, photoValues); 3558 3559 // Check that the photo stored is the expected one. 3560 String displayPhotoUri = getStoredValue(photoUri, StreamItemPhotos.PHOTO_URI); 3561 assertInputStreamContent(loadPhotoFromResource(R.drawable.nebula, PhotoSize.DISPLAY_PHOTO), 3562 mResolver.openInputStream(Uri.parse(displayPhotoUri))); 3563 } 3564 3565 public void testUpdateStreamItemPhotoFromOtherAccount() { 3566 long rawContactId = createRawContact(mAccount); 3567 ContentValues values = buildGenericStreamItemValues(); 3568 Uri resultUri = insertStreamItem(rawContactId, values, mAccount); 3569 long streamItemId = ContentUris.parseId(resultUri); 3570 ContentValues photoValues = buildGenericStreamItemPhotoValues(1); 3571 resultUri = insertStreamItemPhoto(streamItemId, photoValues, mAccount); 3572 long streamItemPhotoId = ContentUris.parseId(resultUri); 3573 3574 photoValues.put(StreamItemPhotos._ID, streamItemPhotoId); 3575 photoValues.put(StreamItemPhotos.PHOTO, loadPhotoFromResource( 3576 R.drawable.galaxy, PhotoSize.ORIGINAL)); 3577 Uri photoUri = 3578 maybeAddAccountQueryParameters( 3579 Uri.withAppendedPath( 3580 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 3581 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 3582 mAccountTwo); 3583 try { 3584 mResolver.update(photoUri, photoValues, null, null); 3585 fail("Should not be able to update stream item photos inserted by another account"); 3586 } catch (SecurityException expected) { 3587 // Can't update a stream item photo inserted by another account. 3588 } 3589 } 3590 3591 // Stream item deletion test cases. 3592 3593 public void testDeleteStreamItemById() { 3594 long rawContactId = createRawContact(); 3595 ContentValues firstValues = buildGenericStreamItemValues(); 3596 Uri resultUri = insertStreamItem(rawContactId, firstValues, null); 3597 long firstStreamItemId = ContentUris.parseId(resultUri); 3598 3599 ContentValues secondValues = buildGenericStreamItemValues(); 3600 secondValues.put(StreamItems.TEXT, "Goodbye world"); 3601 insertStreamItem(rawContactId, secondValues, null); 3602 3603 // Delete the first stream item. 3604 mResolver.delete(ContentUris.withAppendedId(StreamItems.CONTENT_URI, firstStreamItemId), 3605 null, null); 3606 3607 // Check that only the second item remains. 3608 assertStoredValues(Uri.withAppendedPath( 3609 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3610 RawContacts.StreamItems.CONTENT_DIRECTORY), secondValues); 3611 } 3612 3613 public void testDeleteStreamItemWithSelection() { 3614 long rawContactId = createRawContact(); 3615 ContentValues firstValues = buildGenericStreamItemValues(); 3616 insertStreamItem(rawContactId, firstValues, null); 3617 3618 ContentValues secondValues = buildGenericStreamItemValues(); 3619 secondValues.put(StreamItems.TEXT, "Goodbye world"); 3620 insertStreamItem(rawContactId, secondValues, null); 3621 3622 // Delete the first stream item with a custom selection. 3623 mResolver.delete(StreamItems.CONTENT_URI, StreamItems.TEXT + "=?", 3624 new String[]{"Hello world"}); 3625 3626 // Check that only the second item remains. 3627 assertStoredValues(Uri.withAppendedPath( 3628 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3629 RawContacts.StreamItems.CONTENT_DIRECTORY), secondValues); 3630 } 3631 3632 public void testDeleteStreamItemFromOtherAccount() { 3633 long rawContactId = createRawContact(mAccount); 3634 long streamItemId = ContentUris.parseId( 3635 insertStreamItem(rawContactId, buildGenericStreamItemValues(), mAccount)); 3636 try { 3637 mResolver.delete( 3638 maybeAddAccountQueryParameters( 3639 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 3640 mAccountTwo), null, null); 3641 fail("Should not be able to delete stream item inserted by another account"); 3642 } catch (SecurityException expected) { 3643 // Can't delete a stream item from another account. 3644 } 3645 } 3646 3647 // Stream item photo deletion test cases. 3648 3649 public void testDeleteStreamItemPhotoById() { 3650 long rawContactId = createRawContact(); 3651 long streamItemId = ContentUris.parseId( 3652 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null)); 3653 long streamItemPhotoId = ContentUris.parseId( 3654 insertStreamItemPhoto(streamItemId, buildGenericStreamItemPhotoValues(0), null)); 3655 mResolver.delete( 3656 ContentUris.withAppendedId( 3657 Uri.withAppendedPath( 3658 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 3659 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 3660 streamItemPhotoId), null, null); 3661 3662 Cursor c = mResolver.query(StreamItems.CONTENT_PHOTO_URI, 3663 new String[]{StreamItemPhotos._ID}, 3664 StreamItemPhotos.STREAM_ITEM_ID + "=?", new String[]{String.valueOf(streamItemId)}, 3665 null); 3666 try { 3667 assertEquals("Expected photo to be deleted.", 0, c.getCount()); 3668 } finally { 3669 c.close(); 3670 } 3671 } 3672 3673 public void testDeleteStreamItemPhotoWithSelection() { 3674 long rawContactId = createRawContact(); 3675 long streamItemId = ContentUris.parseId( 3676 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null)); 3677 ContentValues firstPhotoValues = buildGenericStreamItemPhotoValues(0); 3678 ContentValues secondPhotoValues = buildGenericStreamItemPhotoValues(1); 3679 insertStreamItemPhoto(streamItemId, firstPhotoValues, null); 3680 firstPhotoValues.remove(StreamItemPhotos.PHOTO); // Removed while processing. 3681 insertStreamItemPhoto(streamItemId, secondPhotoValues, null); 3682 Uri photoUri = Uri.withAppendedPath( 3683 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 3684 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY); 3685 mResolver.delete(photoUri, StreamItemPhotos.SORT_INDEX + "=1", null); 3686 3687 assertStoredValues(photoUri, firstPhotoValues); 3688 } 3689 3690 public void testDeleteStreamItemPhotoFromOtherAccount() { 3691 long rawContactId = createRawContact(mAccount); 3692 long streamItemId = ContentUris.parseId( 3693 insertStreamItem(rawContactId, buildGenericStreamItemValues(), mAccount)); 3694 insertStreamItemPhoto(streamItemId, buildGenericStreamItemPhotoValues(0), mAccount); 3695 try { 3696 mResolver.delete(maybeAddAccountQueryParameters( 3697 Uri.withAppendedPath( 3698 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 3699 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 3700 mAccountTwo), null, null); 3701 fail("Should not be able to delete stream item photo inserted by another account"); 3702 } catch (SecurityException expected) { 3703 // Can't delete a stream item photo from another account. 3704 } 3705 } 3706 3707 public void testDeleteStreamItemsWhenRawContactDeleted() { 3708 long rawContactId = createRawContact(mAccount); 3709 Uri streamItemUri = insertStreamItem(rawContactId, 3710 buildGenericStreamItemValues(), mAccount); 3711 Uri streamItemPhotoUri = insertStreamItemPhoto(ContentUris.parseId(streamItemUri), 3712 buildGenericStreamItemPhotoValues(0), mAccount); 3713 mResolver.delete(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3714 null, null); 3715 3716 ContentValues[] emptyValues = new ContentValues[0]; 3717 3718 // The stream item and its photo should be gone. 3719 assertStoredValues(streamItemUri, emptyValues); 3720 assertStoredValues(streamItemPhotoUri, emptyValues); 3721 } 3722 3723 public void testQueryStreamItemLimit() { 3724 ContentValues values = new ContentValues(); 3725 values.put(StreamItems.MAX_ITEMS, 5); 3726 assertStoredValues(StreamItems.CONTENT_LIMIT_URI, values); 3727 } 3728 3729 // Tests for inserting or updating stream items as a side-effect of making status updates 3730 // (forward-compatibility of status updates into the new social stream API). 3731 3732 public void testStreamItemInsertedOnStatusUpdate() { 3733 3734 // This method of creating a raw contact automatically inserts a status update with 3735 // the status message "hacking". 3736 ContentValues values = new ContentValues(); 3737 long rawContactId = createRawContact(values, "18004664411", 3738 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 3739 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO | 3740 StatusUpdates.CAPABILITY_HAS_VOICE); 3741 3742 ContentValues expectedValues = new ContentValues(); 3743 expectedValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 3744 expectedValues.put(StreamItems.TEXT, "hacking"); 3745 assertStoredValues(RawContacts.CONTENT_URI.buildUpon() 3746 .appendPath(String.valueOf(rawContactId)) 3747 .appendPath(RawContacts.StreamItems.CONTENT_DIRECTORY).build(), 3748 expectedValues); 3749 } 3750 3751 public void testStreamItemInsertedOnStatusUpdate_HtmlQuoting() { 3752 3753 // This method of creating a raw contact automatically inserts a status update with 3754 // the status message "hacking". 3755 ContentValues values = new ContentValues(); 3756 long rawContactId = createRawContact(values, "18004664411", 3757 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 3758 StatusUpdates.CAPABILITY_HAS_VOICE); 3759 3760 // Insert a new status update for the raw contact. 3761 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog411@acme.com", 3762 StatusUpdates.INVISIBLE, "& <b> test '", StatusUpdates.CAPABILITY_HAS_VOICE); 3763 3764 ContentValues expectedValues = new ContentValues(); 3765 expectedValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 3766 expectedValues.put(StreamItems.TEXT, "& <b> test &#39;"); 3767 assertStoredValues(RawContacts.CONTENT_URI.buildUpon() 3768 .appendPath(String.valueOf(rawContactId)) 3769 .appendPath(RawContacts.StreamItems.CONTENT_DIRECTORY).build(), 3770 expectedValues); 3771 } 3772 3773 public void testStreamItemUpdatedOnSecondStatusUpdate() { 3774 3775 // This method of creating a raw contact automatically inserts a status update with 3776 // the status message "hacking". 3777 ContentValues values = new ContentValues(); 3778 int chatMode = StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO | 3779 StatusUpdates.CAPABILITY_HAS_VOICE; 3780 long rawContactId = createRawContact(values, "18004664411", 3781 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, chatMode); 3782 3783 // Insert a new status update for the raw contact. 3784 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog411@acme.com", 3785 StatusUpdates.INVISIBLE, "finished hacking", chatMode); 3786 3787 ContentValues expectedValues = new ContentValues(); 3788 expectedValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 3789 expectedValues.put(StreamItems.TEXT, "finished hacking"); 3790 assertStoredValues(RawContacts.CONTENT_URI.buildUpon() 3791 .appendPath(String.valueOf(rawContactId)) 3792 .appendPath(RawContacts.StreamItems.CONTENT_DIRECTORY).build(), 3793 expectedValues); 3794 } 3795 3796 public void testStreamItemReadRequiresReadSocialStreamPermission() { 3797 long rawContactId = createRawContact(); 3798 long contactId = queryContactId(rawContactId); 3799 String lookupKey = queryLookupKey(contactId); 3800 long streamItemId = ContentUris.parseId( 3801 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null)); 3802 mActor.removePermissions("android.permission.READ_SOCIAL_STREAM"); 3803 3804 // Try selecting the stream item in various ways. 3805 expectSecurityException( 3806 "Querying stream items by contact ID requires social stream read permission", 3807 Uri.withAppendedPath( 3808 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 3809 Contacts.StreamItems.CONTENT_DIRECTORY), null, null, null, null); 3810 3811 expectSecurityException( 3812 "Querying stream items by lookup key requires social stream read permission", 3813 Contacts.CONTENT_LOOKUP_URI.buildUpon().appendPath(lookupKey) 3814 .appendPath(Contacts.StreamItems.CONTENT_DIRECTORY).build(), 3815 null, null, null, null); 3816 3817 expectSecurityException( 3818 "Querying stream items by lookup key and ID requires social stream read permission", 3819 Uri.withAppendedPath(Contacts.getLookupUri(contactId, lookupKey), 3820 Contacts.StreamItems.CONTENT_DIRECTORY), 3821 null, null, null, null); 3822 3823 expectSecurityException( 3824 "Querying stream items by raw contact ID requires social stream read permission", 3825 Uri.withAppendedPath( 3826 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3827 RawContacts.StreamItems.CONTENT_DIRECTORY), null, null, null, null); 3828 3829 expectSecurityException( 3830 "Querying stream items by raw contact ID and stream item ID requires social " + 3831 "stream read permission", 3832 ContentUris.withAppendedId( 3833 Uri.withAppendedPath( 3834 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3835 RawContacts.StreamItems.CONTENT_DIRECTORY), 3836 streamItemId), null, null, null, null); 3837 3838 expectSecurityException( 3839 "Querying all stream items requires social stream read permission", 3840 StreamItems.CONTENT_URI, null, null, null, null); 3841 3842 expectSecurityException( 3843 "Querying stream item by ID requires social stream read permission", 3844 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 3845 null, null, null, null); 3846 } 3847 3848 public void testStreamItemPhotoReadRequiresReadSocialStreamPermission() { 3849 long rawContactId = createRawContact(); 3850 long streamItemId = ContentUris.parseId( 3851 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null)); 3852 long streamItemPhotoId = ContentUris.parseId( 3853 insertStreamItemPhoto(streamItemId, buildGenericStreamItemPhotoValues(0), null)); 3854 mActor.removePermissions("android.permission.READ_SOCIAL_STREAM"); 3855 3856 // Try selecting the stream item photo in various ways. 3857 expectSecurityException( 3858 "Querying all stream item photos requires social stream read permission", 3859 StreamItems.CONTENT_URI.buildUpon() 3860 .appendPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY).build(), 3861 null, null, null, null); 3862 3863 expectSecurityException( 3864 "Querying all stream item photos requires social stream read permission", 3865 StreamItems.CONTENT_URI.buildUpon() 3866 .appendPath(String.valueOf(streamItemId)) 3867 .appendPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY) 3868 .appendPath(String.valueOf(streamItemPhotoId)).build(), 3869 null, null, null, null); 3870 } 3871 3872 public void testStreamItemModificationRequiresWriteSocialStreamPermission() { 3873 long rawContactId = createRawContact(); 3874 long streamItemId = ContentUris.parseId( 3875 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null)); 3876 mActor.removePermissions("android.permission.WRITE_SOCIAL_STREAM"); 3877 3878 try { 3879 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null); 3880 fail("Should not be able to insert to stream without write social stream permission"); 3881 } catch (SecurityException expected) { 3882 } 3883 3884 try { 3885 ContentValues values = new ContentValues(); 3886 values.put(StreamItems.TEXT, "Goodbye world"); 3887 mResolver.update(ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 3888 values, null, null); 3889 fail("Should not be able to update stream without write social stream permission"); 3890 } catch (SecurityException expected) { 3891 } 3892 3893 try { 3894 mResolver.delete(ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 3895 null, null); 3896 fail("Should not be able to delete from stream without write social stream permission"); 3897 } catch (SecurityException expected) { 3898 } 3899 } 3900 3901 public void testStreamItemPhotoModificationRequiresWriteSocialStreamPermission() { 3902 long rawContactId = createRawContact(); 3903 long streamItemId = ContentUris.parseId( 3904 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null)); 3905 long streamItemPhotoId = ContentUris.parseId( 3906 insertStreamItemPhoto(streamItemId, buildGenericStreamItemPhotoValues(0), null)); 3907 mActor.removePermissions("android.permission.WRITE_SOCIAL_STREAM"); 3908 3909 Uri photoUri = StreamItems.CONTENT_URI.buildUpon() 3910 .appendPath(String.valueOf(streamItemId)) 3911 .appendPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY) 3912 .appendPath(String.valueOf(streamItemPhotoId)).build(); 3913 3914 try { 3915 insertStreamItemPhoto(streamItemId, buildGenericStreamItemPhotoValues(1), null); 3916 fail("Should not be able to insert photos without write social stream permission"); 3917 } catch (SecurityException expected) { 3918 } 3919 3920 try { 3921 ContentValues values = new ContentValues(); 3922 values.put(StreamItemPhotos.PHOTO, loadPhotoFromResource(R.drawable.galaxy, 3923 PhotoSize.ORIGINAL)); 3924 mResolver.update(photoUri, values, null, null); 3925 fail("Should not be able to update photos without write social stream permission"); 3926 } catch (SecurityException expected) { 3927 } 3928 3929 try { 3930 mResolver.delete(photoUri, null, null); 3931 fail("Should not be able to delete photos without write social stream permission"); 3932 } catch (SecurityException expected) { 3933 } 3934 } 3935 3936 public void testStatusUpdateDoesNotRequireReadOrWriteSocialStreamPermission() { 3937 int protocol1 = Im.PROTOCOL_GOOGLE_TALK; 3938 String handle1 = "test@gmail.com"; 3939 long rawContactId = createRawContact(); 3940 insertImHandle(rawContactId, protocol1, null, handle1); 3941 mActor.removePermissions("android.permission.READ_SOCIAL_STREAM"); 3942 mActor.removePermissions("android.permission.WRITE_SOCIAL_STREAM"); 3943 3944 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AVAILABLE, "Green", 3945 StatusUpdates.CAPABILITY_HAS_CAMERA); 3946 3947 mActor.addPermissions("android.permission.READ_SOCIAL_STREAM"); 3948 3949 ContentValues expectedValues = new ContentValues(); 3950 expectedValues.put(StreamItems.TEXT, "Green"); 3951 assertStoredValues(Uri.withAppendedPath( 3952 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 3953 RawContacts.StreamItems.CONTENT_DIRECTORY), expectedValues); 3954 } 3955 3956 private ContentValues buildGenericStreamItemValues() { 3957 ContentValues values = new ContentValues(); 3958 values.put(StreamItems.TEXT, "Hello world"); 3959 values.put(StreamItems.TIMESTAMP, System.currentTimeMillis()); 3960 values.put(StreamItems.COMMENTS, "Reshared by 123 others"); 3961 return values; 3962 } 3963 3964 private ContentValues buildGenericStreamItemPhotoValues(int sortIndex) { 3965 ContentValues values = new ContentValues(); 3966 values.put(StreamItemPhotos.SORT_INDEX, sortIndex); 3967 values.put(StreamItemPhotos.PHOTO, 3968 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.ORIGINAL)); 3969 return values; 3970 } 3971 3972 public void testSingleStatusUpdateRowPerContact() { 3973 int protocol1 = Im.PROTOCOL_GOOGLE_TALK; 3974 String handle1 = "test@gmail.com"; 3975 3976 long rawContactId1 = createRawContact(); 3977 insertImHandle(rawContactId1, protocol1, null, handle1); 3978 3979 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AVAILABLE, "Green", 3980 StatusUpdates.CAPABILITY_HAS_CAMERA); 3981 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AWAY, "Yellow", 3982 StatusUpdates.CAPABILITY_HAS_CAMERA); 3983 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.INVISIBLE, "Red", 3984 StatusUpdates.CAPABILITY_HAS_CAMERA); 3985 3986 Cursor c = queryContact(queryContactId(rawContactId1), 3987 new String[] {Contacts.CONTACT_PRESENCE, Contacts.CONTACT_STATUS}); 3988 assertEquals(1, c.getCount()); 3989 3990 c.moveToFirst(); 3991 assertEquals(StatusUpdates.INVISIBLE, c.getInt(0)); 3992 assertEquals("Red", c.getString(1)); 3993 c.close(); 3994 } 3995 3996 private void updateSendToVoicemailAndRingtone(long contactId, boolean sendToVoicemail, 3997 String ringtone) { 3998 ContentValues values = new ContentValues(); 3999 values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail); 4000 if (ringtone != null) { 4001 values.put(Contacts.CUSTOM_RINGTONE, ringtone); 4002 } 4003 4004 final Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 4005 int count = mResolver.update(uri, values, null, null); 4006 assertEquals(1, count); 4007 } 4008 4009 private void updateSendToVoicemailAndRingtoneWithSelection(long contactId, 4010 boolean sendToVoicemail, String ringtone) { 4011 ContentValues values = new ContentValues(); 4012 values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail); 4013 if (ringtone != null) { 4014 values.put(Contacts.CUSTOM_RINGTONE, ringtone); 4015 } 4016 4017 int count = mResolver.update(Contacts.CONTENT_URI, values, Contacts._ID + "=" + contactId, 4018 null); 4019 assertEquals(1, count); 4020 } 4021 4022 private void assertSendToVoicemailAndRingtone(long contactId, boolean expectedSendToVoicemail, 4023 String expectedRingtone) { 4024 Cursor c = queryContact(contactId); 4025 assertTrue(c.moveToNext()); 4026 int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL)); 4027 assertEquals(expectedSendToVoicemail ? 1 : 0, sendToVoicemail); 4028 String ringtone = c.getString(c.getColumnIndex(Contacts.CUSTOM_RINGTONE)); 4029 if (expectedRingtone == null) { 4030 assertNull(ringtone); 4031 } else { 4032 assertTrue(ArrayUtils.contains(expectedRingtone.split(","), ringtone)); 4033 } 4034 c.close(); 4035 } 4036 4037 public void testContactVisibilityUpdateOnMembershipChange() { 4038 long rawContactId = createRawContact(mAccount); 4039 assertVisibility(rawContactId, "0"); 4040 4041 long visibleGroupId = createGroup(mAccount, "123", "Visible", 1); 4042 long invisibleGroupId = createGroup(mAccount, "567", "Invisible", 0); 4043 4044 Uri membership1 = insertGroupMembership(rawContactId, visibleGroupId); 4045 assertVisibility(rawContactId, "1"); 4046 4047 Uri membership2 = insertGroupMembership(rawContactId, invisibleGroupId); 4048 assertVisibility(rawContactId, "1"); 4049 4050 mResolver.delete(membership1, null, null); 4051 assertVisibility(rawContactId, "0"); 4052 4053 ContentValues values = new ContentValues(); 4054 values.put(GroupMembership.GROUP_ROW_ID, visibleGroupId); 4055 4056 mResolver.update(membership2, values, null, null); 4057 assertVisibility(rawContactId, "1"); 4058 } 4059 4060 private void assertVisibility(long rawContactId, String expectedValue) { 4061 assertStoredValue(Contacts.CONTENT_URI, Contacts._ID + "=" + queryContactId(rawContactId), 4062 null, Contacts.IN_VISIBLE_GROUP, expectedValue); 4063 } 4064 4065 public void testSupplyingBothValuesAndParameters() throws Exception { 4066 Account account = new Account("account 1", "type%/:1"); 4067 Uri uri = ContactsContract.Groups.CONTENT_URI.buildUpon() 4068 .appendQueryParameter(ContactsContract.Groups.ACCOUNT_NAME, account.name) 4069 .appendQueryParameter(ContactsContract.Groups.ACCOUNT_TYPE, account.type) 4070 .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true") 4071 .build(); 4072 4073 ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(uri); 4074 builder.withValue(ContactsContract.Groups.ACCOUNT_TYPE, account.type); 4075 builder.withValue(ContactsContract.Groups.ACCOUNT_NAME, account.name); 4076 builder.withValue(ContactsContract.Groups.SYSTEM_ID, "some id"); 4077 builder.withValue(ContactsContract.Groups.TITLE, "some name"); 4078 builder.withValue(ContactsContract.Groups.GROUP_VISIBLE, 1); 4079 4080 mResolver.applyBatch(ContactsContract.AUTHORITY, Lists.newArrayList(builder.build())); 4081 4082 builder = ContentProviderOperation.newInsert(uri); 4083 builder.withValue(ContactsContract.Groups.ACCOUNT_TYPE, account.type + "diff"); 4084 builder.withValue(ContactsContract.Groups.ACCOUNT_NAME, account.name); 4085 builder.withValue(ContactsContract.Groups.SYSTEM_ID, "some other id"); 4086 builder.withValue(ContactsContract.Groups.TITLE, "some other name"); 4087 builder.withValue(ContactsContract.Groups.GROUP_VISIBLE, 1); 4088 4089 try { 4090 mResolver.applyBatch(ContactsContract.AUTHORITY, Lists.newArrayList(builder.build())); 4091 fail("Expected IllegalArgumentException"); 4092 } catch (IllegalArgumentException ex) { 4093 // Expected 4094 } 4095 } 4096 4097 public void testContentEntityIterator() { 4098 // create multiple contacts and check that the selected ones are returned 4099 long id; 4100 4101 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 4102 long groupId2 = createGroup(mAccount, "gsid2", "title2"); 4103 4104 id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c0"); 4105 insertGroupMembership(id, "gsid1"); 4106 insertEmail(id, "c0@email.com"); 4107 insertPhoneNumber(id, "5551212c0"); 4108 4109 long c1 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c1"); 4110 Uri id_1_0 = insertGroupMembership(id, "gsid1"); 4111 Uri id_1_1 = insertGroupMembership(id, "gsid2"); 4112 Uri id_1_2 = insertEmail(id, "c1@email.com"); 4113 Uri id_1_3 = insertPhoneNumber(id, "5551212c1"); 4114 4115 long c2 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c2"); 4116 Uri id_2_0 = insertGroupMembership(id, "gsid1"); 4117 Uri id_2_1 = insertEmail(id, "c2@email.com"); 4118 Uri id_2_2 = insertPhoneNumber(id, "5551212c2"); 4119 4120 long c3 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c3"); 4121 Uri id_3_0 = insertGroupMembership(id, groupId2); 4122 Uri id_3_1 = insertEmail(id, "c3@email.com"); 4123 Uri id_3_2 = insertPhoneNumber(id, "5551212c3"); 4124 4125 EntityIterator iterator = RawContacts.newEntityIterator(mResolver.query( 4126 maybeAddAccountQueryParameters(RawContactsEntity.CONTENT_URI, mAccount), null, 4127 RawContacts.SOURCE_ID + " in ('c1', 'c2', 'c3')", null, null)); 4128 Entity entity; 4129 ContentValues[] subValues; 4130 entity = iterator.next(); 4131 assertEquals(c1, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 4132 subValues = asSortedContentValuesArray(entity.getSubValues()); 4133 assertEquals(4, subValues.length); 4134 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 4135 Data._ID, id_1_0, 4136 GroupMembership.GROUP_ROW_ID, groupId1, 4137 GroupMembership.GROUP_SOURCE_ID, "gsid1"); 4138 assertDataRow(subValues[1], GroupMembership.CONTENT_ITEM_TYPE, 4139 Data._ID, id_1_1, 4140 GroupMembership.GROUP_ROW_ID, groupId2, 4141 GroupMembership.GROUP_SOURCE_ID, "gsid2"); 4142 assertDataRow(subValues[2], Email.CONTENT_ITEM_TYPE, 4143 Data._ID, id_1_2, 4144 Email.DATA, "c1@email.com"); 4145 assertDataRow(subValues[3], Phone.CONTENT_ITEM_TYPE, 4146 Data._ID, id_1_3, 4147 Email.DATA, "5551212c1"); 4148 4149 entity = iterator.next(); 4150 assertEquals(c2, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 4151 subValues = asSortedContentValuesArray(entity.getSubValues()); 4152 assertEquals(3, subValues.length); 4153 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 4154 Data._ID, id_2_0, 4155 GroupMembership.GROUP_ROW_ID, groupId1, 4156 GroupMembership.GROUP_SOURCE_ID, "gsid1"); 4157 assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE, 4158 Data._ID, id_2_1, 4159 Email.DATA, "c2@email.com"); 4160 assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE, 4161 Data._ID, id_2_2, 4162 Email.DATA, "5551212c2"); 4163 4164 entity = iterator.next(); 4165 assertEquals(c3, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 4166 subValues = asSortedContentValuesArray(entity.getSubValues()); 4167 assertEquals(3, subValues.length); 4168 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 4169 Data._ID, id_3_0, 4170 GroupMembership.GROUP_ROW_ID, groupId2, 4171 GroupMembership.GROUP_SOURCE_ID, "gsid2"); 4172 assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE, 4173 Data._ID, id_3_1, 4174 Email.DATA, "c3@email.com"); 4175 assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE, 4176 Data._ID, id_3_2, 4177 Email.DATA, "5551212c3"); 4178 4179 assertFalse(iterator.hasNext()); 4180 iterator.close(); 4181 } 4182 4183 public void testDataCreateUpdateDeleteByMimeType() throws Exception { 4184 long rawContactId = createRawContact(); 4185 4186 ContentValues values = new ContentValues(); 4187 values.put(Data.RAW_CONTACT_ID, rawContactId); 4188 values.put(Data.MIMETYPE, "testmimetype"); 4189 values.put(Data.RES_PACKAGE, "oldpackage"); 4190 values.put(Data.IS_PRIMARY, 1); 4191 values.put(Data.IS_SUPER_PRIMARY, 1); 4192 values.put(Data.DATA1, "old1"); 4193 values.put(Data.DATA2, "old2"); 4194 values.put(Data.DATA3, "old3"); 4195 values.put(Data.DATA4, "old4"); 4196 values.put(Data.DATA5, "old5"); 4197 values.put(Data.DATA6, "old6"); 4198 values.put(Data.DATA7, "old7"); 4199 values.put(Data.DATA8, "old8"); 4200 values.put(Data.DATA9, "old9"); 4201 values.put(Data.DATA10, "old10"); 4202 values.put(Data.DATA11, "old11"); 4203 values.put(Data.DATA12, "old12"); 4204 values.put(Data.DATA13, "old13"); 4205 values.put(Data.DATA14, "old14"); 4206 values.put(Data.DATA15, "old15"); 4207 Uri uri = mResolver.insert(Data.CONTENT_URI, values); 4208 assertStoredValues(uri, values); 4209 assertNetworkNotified(true); 4210 4211 values.clear(); 4212 values.put(Data.RES_PACKAGE, "newpackage"); 4213 values.put(Data.IS_PRIMARY, 0); 4214 values.put(Data.IS_SUPER_PRIMARY, 0); 4215 values.put(Data.DATA1, "new1"); 4216 values.put(Data.DATA2, "new2"); 4217 values.put(Data.DATA3, "new3"); 4218 values.put(Data.DATA4, "new4"); 4219 values.put(Data.DATA5, "new5"); 4220 values.put(Data.DATA6, "new6"); 4221 values.put(Data.DATA7, "new7"); 4222 values.put(Data.DATA8, "new8"); 4223 values.put(Data.DATA9, "new9"); 4224 values.put(Data.DATA10, "new10"); 4225 values.put(Data.DATA11, "new11"); 4226 values.put(Data.DATA12, "new12"); 4227 values.put(Data.DATA13, "new13"); 4228 values.put(Data.DATA14, "new14"); 4229 values.put(Data.DATA15, "new15"); 4230 mResolver.update(Data.CONTENT_URI, values, Data.RAW_CONTACT_ID + "=" + rawContactId + 4231 " AND " + Data.MIMETYPE + "='testmimetype'", null); 4232 assertNetworkNotified(true); 4233 4234 assertStoredValues(uri, values); 4235 4236 int count = mResolver.delete(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId 4237 + " AND " + Data.MIMETYPE + "='testmimetype'", null); 4238 assertEquals(1, count); 4239 assertEquals(0, getCount(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId 4240 + " AND " + Data.MIMETYPE + "='testmimetype'", null)); 4241 assertNetworkNotified(true); 4242 } 4243 4244 public void testRawContactQuery() { 4245 Account account1 = new Account("a", "b"); 4246 Account account2 = new Account("c", "d"); 4247 long rawContactId1 = createRawContact(account1); 4248 long rawContactId2 = createRawContact(account2); 4249 4250 Uri uri1 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account1); 4251 Uri uri2 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account2); 4252 assertEquals(1, getCount(uri1, null, null)); 4253 assertEquals(1, getCount(uri2, null, null)); 4254 assertStoredValue(uri1, RawContacts._ID, rawContactId1) ; 4255 assertStoredValue(uri2, RawContacts._ID, rawContactId2) ; 4256 4257 Uri rowUri1 = ContentUris.withAppendedId(uri1, rawContactId1); 4258 Uri rowUri2 = ContentUris.withAppendedId(uri2, rawContactId2); 4259 assertStoredValue(rowUri1, RawContacts._ID, rawContactId1) ; 4260 assertStoredValue(rowUri2, RawContacts._ID, rawContactId2) ; 4261 } 4262 4263 public void testRawContactDeletion() { 4264 long rawContactId = createRawContact(mAccount); 4265 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 4266 4267 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 4268 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 4269 StatusUpdates.AVAILABLE, null, 4270 StatusUpdates.CAPABILITY_HAS_CAMERA); 4271 long contactId = queryContactId(rawContactId); 4272 4273 assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 4274 null, null)); 4275 assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 4276 + rawContactId, null)); 4277 4278 mResolver.delete(uri, null, null); 4279 4280 assertStoredValue(uri, RawContacts.DELETED, "1"); 4281 assertNetworkNotified(true); 4282 4283 Uri permanentDeletionUri = setCallerIsSyncAdapter(uri, mAccount); 4284 mResolver.delete(permanentDeletionUri, null, null); 4285 assertEquals(0, getCount(uri, null, null)); 4286 assertEquals(0, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 4287 null, null)); 4288 assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 4289 + rawContactId, null)); 4290 assertEquals(0, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null)); 4291 assertNetworkNotified(false); 4292 } 4293 4294 public void testRawContactDeletionKeepingAggregateContact() { 4295 long rawContactId1 = createRawContactWithName(mAccount); 4296 long rawContactId2 = createRawContactWithName(mAccount); 4297 setAggregationException( 4298 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 4299 4300 long contactId = queryContactId(rawContactId1); 4301 4302 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 4303 Uri permanentDeletionUri = setCallerIsSyncAdapter(uri, mAccount); 4304 mResolver.delete(permanentDeletionUri, null, null); 4305 assertEquals(0, getCount(uri, null, null)); 4306 assertEquals(1, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null)); 4307 } 4308 4309 public void testRawContactDeletionWithAccounts() { 4310 long rawContactId = createRawContact(mAccount); 4311 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 4312 4313 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 4314 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 4315 StatusUpdates.AVAILABLE, null, 4316 StatusUpdates.CAPABILITY_HAS_CAMERA); 4317 assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 4318 null, null)); 4319 assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 4320 + rawContactId, null)); 4321 4322 // Do not delete if we are deleting with wrong account. 4323 Uri deleteWithWrongAccountUri = 4324 RawContacts.CONTENT_URI.buildUpon() 4325 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccountTwo.name) 4326 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccountTwo.type) 4327 .build(); 4328 mResolver.delete(deleteWithWrongAccountUri, null, null); 4329 4330 assertStoredValue(uri, RawContacts.DELETED, "0"); 4331 4332 // Delete if we are deleting with correct account. 4333 Uri deleteWithCorrectAccountUri = 4334 RawContacts.CONTENT_URI.buildUpon() 4335 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccount.name) 4336 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccount.type) 4337 .build(); 4338 mResolver.delete(deleteWithCorrectAccountUri, null, null); 4339 4340 assertStoredValue(uri, RawContacts.DELETED, "1"); 4341 } 4342 4343 public void testAccountsUpdated() { 4344 // This is to ensure we do not delete contacts with null, null (account name, type) 4345 // accidentally. 4346 long rawContactId3 = createRawContactWithName("James", "Sullivan"); 4347 insertPhoneNumber(rawContactId3, "5234567890"); 4348 Uri rawContact3 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId3); 4349 assertEquals(1, getCount(RawContacts.CONTENT_URI, null, null)); 4350 4351 ContactsProvider2 cp = (ContactsProvider2) getProvider(); 4352 mActor.setAccounts(new Account[]{mAccount, mAccountTwo}); 4353 cp.onAccountsUpdated(new Account[]{mAccount, mAccountTwo}); 4354 assertEquals(1, getCount(RawContacts.CONTENT_URI, null, null)); 4355 assertStoredValue(rawContact3, RawContacts.ACCOUNT_NAME, null); 4356 assertStoredValue(rawContact3, RawContacts.ACCOUNT_TYPE, null); 4357 4358 long rawContactId1 = createRawContact(mAccount); 4359 insertEmail(rawContactId1, "account1@email.com"); 4360 long rawContactId2 = createRawContact(mAccountTwo); 4361 insertEmail(rawContactId2, "account2@email.com"); 4362 insertImHandle(rawContactId2, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 4363 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 4364 StatusUpdates.AVAILABLE, null, 4365 StatusUpdates.CAPABILITY_HAS_CAMERA); 4366 4367 mActor.setAccounts(new Account[]{mAccount}); 4368 cp.onAccountsUpdated(new Account[]{mAccount}); 4369 assertEquals(2, getCount(RawContacts.CONTENT_URI, null, null)); 4370 assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 4371 + rawContactId2, null)); 4372 } 4373 4374 public void testAccountDeletion() { 4375 Account readOnlyAccount = new Account("act", READ_ONLY_ACCOUNT_TYPE); 4376 ContactsProvider2 cp = (ContactsProvider2) getProvider(); 4377 mActor.setAccounts(new Account[]{readOnlyAccount, mAccount}); 4378 cp.onAccountsUpdated(new Account[]{readOnlyAccount, mAccount}); 4379 4380 long rawContactId1 = createRawContactWithName("John", "Doe", readOnlyAccount); 4381 Uri photoUri1 = insertPhoto(rawContactId1); 4382 long rawContactId2 = createRawContactWithName("john", "doe", mAccount); 4383 Uri photoUri2 = insertPhoto(rawContactId2); 4384 storeValue(photoUri2, Photo.IS_SUPER_PRIMARY, "1"); 4385 4386 assertAggregated(rawContactId1, rawContactId2); 4387 4388 long contactId = queryContactId(rawContactId1); 4389 4390 // The display name should come from the writable account 4391 assertStoredValue(Uri.withAppendedPath( 4392 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 4393 Contacts.Data.CONTENT_DIRECTORY), 4394 Contacts.DISPLAY_NAME, "john doe"); 4395 4396 // The photo should be the one we marked as super-primary 4397 assertStoredValue(Contacts.CONTENT_URI, contactId, 4398 Contacts.PHOTO_ID, ContentUris.parseId(photoUri2)); 4399 4400 mActor.setAccounts(new Account[]{readOnlyAccount}); 4401 // Remove the writable account 4402 cp.onAccountsUpdated(new Account[]{readOnlyAccount}); 4403 4404 // The display name should come from the remaining account 4405 assertStoredValue(Uri.withAppendedPath( 4406 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 4407 Contacts.Data.CONTENT_DIRECTORY), 4408 Contacts.DISPLAY_NAME, "John Doe"); 4409 4410 // The photo should be the remaining one 4411 assertStoredValue(Contacts.CONTENT_URI, contactId, 4412 Contacts.PHOTO_ID, ContentUris.parseId(photoUri1)); 4413 } 4414 4415 public void testStreamItemsCleanedUpOnAccountRemoval() { 4416 Account doomedAccount = new Account("doom", "doom"); 4417 Account safeAccount = mAccount; 4418 ContactsProvider2 cp = (ContactsProvider2) getProvider(); 4419 mActor.setAccounts(new Account[]{doomedAccount, safeAccount}); 4420 cp.onAccountsUpdated(new Account[]{doomedAccount, safeAccount}); 4421 4422 // Create a doomed raw contact, stream item, and photo. 4423 long doomedRawContactId = createRawContactWithName(doomedAccount); 4424 Uri doomedStreamItemUri = 4425 insertStreamItem(doomedRawContactId, buildGenericStreamItemValues(), doomedAccount); 4426 long doomedStreamItemId = ContentUris.parseId(doomedStreamItemUri); 4427 Uri doomedStreamItemPhotoUri = insertStreamItemPhoto( 4428 doomedStreamItemId, buildGenericStreamItemPhotoValues(0), doomedAccount); 4429 4430 // Create a safe raw contact, stream item, and photo. 4431 long safeRawContactId = createRawContactWithName(safeAccount); 4432 Uri safeStreamItemUri = 4433 insertStreamItem(safeRawContactId, buildGenericStreamItemValues(), safeAccount); 4434 long safeStreamItemId = ContentUris.parseId(safeStreamItemUri); 4435 Uri safeStreamItemPhotoUri = insertStreamItemPhoto( 4436 safeStreamItemId, buildGenericStreamItemPhotoValues(0), safeAccount); 4437 long safeStreamItemPhotoId = ContentUris.parseId(safeStreamItemPhotoUri); 4438 4439 // Remove the doomed account. 4440 mActor.setAccounts(new Account[]{safeAccount}); 4441 cp.onAccountsUpdated(new Account[]{safeAccount}); 4442 4443 // Check that the doomed stuff has all been nuked. 4444 ContentValues[] noValues = new ContentValues[0]; 4445 assertStoredValues(ContentUris.withAppendedId(RawContacts.CONTENT_URI, doomedRawContactId), 4446 noValues); 4447 assertStoredValues(doomedStreamItemUri, noValues); 4448 assertStoredValues(doomedStreamItemPhotoUri, noValues); 4449 4450 // Check that the safe stuff lives on. 4451 assertStoredValue(RawContacts.CONTENT_URI, safeRawContactId, RawContacts._ID, 4452 safeRawContactId); 4453 assertStoredValue(safeStreamItemUri, StreamItems._ID, safeStreamItemId); 4454 assertStoredValue(safeStreamItemPhotoUri, StreamItemPhotos._ID, safeStreamItemPhotoId); 4455 } 4456 4457 public void testContactDeletion() { 4458 long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1); 4459 long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_2); 4460 4461 long contactId = queryContactId(rawContactId1); 4462 4463 mResolver.delete(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), null, null); 4464 4465 assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1), 4466 RawContacts.DELETED, "1"); 4467 assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2), 4468 RawContacts.DELETED, "1"); 4469 } 4470 4471 public void testMarkAsDirtyParameter() { 4472 long rawContactId = createRawContact(mAccount); 4473 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 4474 4475 Uri uri = insertStructuredName(rawContactId, "John", "Doe"); 4476 clearDirty(rawContactUri); 4477 Uri updateUri = setCallerIsSyncAdapter(uri, mAccount); 4478 4479 ContentValues values = new ContentValues(); 4480 values.put(StructuredName.FAMILY_NAME, "Dough"); 4481 mResolver.update(updateUri, values, null, null); 4482 assertStoredValue(uri, StructuredName.FAMILY_NAME, "Dough"); 4483 assertDirty(rawContactUri, false); 4484 assertNetworkNotified(false); 4485 } 4486 4487 public void testRawContactDirtyAndVersion() { 4488 final long rawContactId = createRawContact(mAccount); 4489 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId); 4490 assertDirty(uri, false); 4491 long version = getVersion(uri); 4492 4493 ContentValues values = new ContentValues(); 4494 values.put(ContactsContract.RawContacts.DIRTY, 0); 4495 values.put(ContactsContract.RawContacts.SEND_TO_VOICEMAIL, 1); 4496 values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 4497 RawContacts.AGGREGATION_MODE_IMMEDIATE); 4498 values.put(ContactsContract.RawContacts.STARRED, 1); 4499 assertEquals(1, mResolver.update(uri, values, null, null)); 4500 assertEquals(version, getVersion(uri)); 4501 4502 assertDirty(uri, false); 4503 assertNetworkNotified(false); 4504 4505 Uri emailUri = insertEmail(rawContactId, "goo@woo.com"); 4506 assertDirty(uri, true); 4507 assertNetworkNotified(true); 4508 ++version; 4509 assertEquals(version, getVersion(uri)); 4510 clearDirty(uri); 4511 4512 values = new ContentValues(); 4513 values.put(Email.DATA, "goo@hoo.com"); 4514 mResolver.update(emailUri, values, null, null); 4515 assertDirty(uri, true); 4516 assertNetworkNotified(true); 4517 ++version; 4518 assertEquals(version, getVersion(uri)); 4519 clearDirty(uri); 4520 4521 mResolver.delete(emailUri, null, null); 4522 assertDirty(uri, true); 4523 assertNetworkNotified(true); 4524 ++version; 4525 assertEquals(version, getVersion(uri)); 4526 } 4527 4528 public void testRawContactClearDirty() { 4529 final long rawContactId = createRawContact(mAccount); 4530 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, 4531 rawContactId); 4532 long version = getVersion(uri); 4533 insertEmail(rawContactId, "goo@woo.com"); 4534 assertDirty(uri, true); 4535 version++; 4536 assertEquals(version, getVersion(uri)); 4537 4538 clearDirty(uri); 4539 assertDirty(uri, false); 4540 assertEquals(version, getVersion(uri)); 4541 } 4542 4543 public void testRawContactDeletionSetsDirty() { 4544 final long rawContactId = createRawContact(mAccount); 4545 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, 4546 rawContactId); 4547 long version = getVersion(uri); 4548 clearDirty(uri); 4549 assertDirty(uri, false); 4550 4551 mResolver.delete(uri, null, null); 4552 assertStoredValue(uri, RawContacts.DELETED, "1"); 4553 assertDirty(uri, true); 4554 assertNetworkNotified(true); 4555 version++; 4556 assertEquals(version, getVersion(uri)); 4557 } 4558 4559 public void testDeleteContactWithoutName() { 4560 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues()); 4561 long rawContactId = ContentUris.parseId(rawContactUri); 4562 4563 Uri phoneUri = insertPhoneNumber(rawContactId, "555-123-45678", true); 4564 4565 long contactId = queryContactId(rawContactId); 4566 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 4567 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 4568 4569 int numDeleted = mResolver.delete(lookupUri, null, null); 4570 assertEquals(1, numDeleted); 4571 } 4572 4573 public void testDeleteContactWithoutAnyData() { 4574 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues()); 4575 long rawContactId = ContentUris.parseId(rawContactUri); 4576 4577 long contactId = queryContactId(rawContactId); 4578 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 4579 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 4580 4581 int numDeleted = mResolver.delete(lookupUri, null, null); 4582 assertEquals(1, numDeleted); 4583 } 4584 4585 public void testDeleteContactWithEscapedUri() { 4586 ContentValues values = new ContentValues(); 4587 values.put(RawContacts.SOURCE_ID, "!@#$%^&*()_+=-/.,<>?;'\":[]}{\\|`~"); 4588 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 4589 long rawContactId = ContentUris.parseId(rawContactUri); 4590 4591 long contactId = queryContactId(rawContactId); 4592 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 4593 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 4594 assertEquals(1, mResolver.delete(lookupUri, null, null)); 4595 } 4596 4597 public void testQueryContactWithEscapedUri() { 4598 ContentValues values = new ContentValues(); 4599 values.put(RawContacts.SOURCE_ID, "!@#$%^&*()_+=-/.,<>?;'\":[]}{\\|`~"); 4600 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 4601 long rawContactId = ContentUris.parseId(rawContactUri); 4602 4603 long contactId = queryContactId(rawContactId); 4604 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 4605 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 4606 Cursor c = mResolver.query(lookupUri, null, null, null, ""); 4607 assertEquals(1, c.getCount()); 4608 c.close(); 4609 } 4610 4611 public void testGetPhotoUri() { 4612 ContentValues values = new ContentValues(); 4613 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 4614 long rawContactId = ContentUris.parseId(rawContactUri); 4615 insertStructuredName(rawContactId, "John", "Doe"); 4616 long dataId = ContentUris.parseId(insertPhoto(rawContactId, R.drawable.earth_normal)); 4617 long photoFileId = getStoredLongValue(Data.CONTENT_URI, Data._ID + "=?", 4618 new String[]{String.valueOf(dataId)}, Photo.PHOTO_FILE_ID); 4619 String photoUri = ContentUris.withAppendedId(DisplayPhoto.CONTENT_URI, photoFileId) 4620 .toString(); 4621 4622 assertStoredValue( 4623 ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(rawContactId)), 4624 Contacts.PHOTO_URI, photoUri); 4625 } 4626 4627 public void testGetPhotoViaLookupUri() throws IOException { 4628 long rawContactId = createRawContact(); 4629 long contactId = queryContactId(rawContactId); 4630 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 4631 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 4632 String lookupKey = lookupUri.getPathSegments().get(2); 4633 insertPhoto(rawContactId, R.drawable.earth_small); 4634 byte[] thumbnail = loadPhotoFromResource(R.drawable.earth_small, PhotoSize.THUMBNAIL); 4635 4636 // Two forms of lookup key URIs should be valid - one with the contact ID, one without. 4637 Uri photoLookupUriWithId = Uri.withAppendedPath(lookupUri, "photo"); 4638 Uri photoLookupUriWithoutId = Contacts.CONTENT_LOOKUP_URI.buildUpon() 4639 .appendPath(lookupKey).appendPath("photo").build(); 4640 4641 // Try retrieving as a data record. 4642 ContentValues values = new ContentValues(); 4643 values.put(Photo.PHOTO, thumbnail); 4644 assertStoredValues(photoLookupUriWithId, values); 4645 assertStoredValues(photoLookupUriWithoutId, values); 4646 4647 // Try opening as an input stream. 4648 assertInputStreamContent(thumbnail, mResolver.openInputStream(photoLookupUriWithId)); 4649 assertInputStreamContent(thumbnail, mResolver.openInputStream(photoLookupUriWithoutId)); 4650 } 4651 4652 public void testInputStreamForPhoto() throws Exception { 4653 long rawContactId = createRawContact(); 4654 long contactId = queryContactId(rawContactId); 4655 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 4656 insertPhoto(rawContactId); 4657 Uri photoUri = Uri.parse(getStoredValue(contactUri, Contacts.PHOTO_URI)); 4658 Uri photoThumbnailUri = Uri.parse(getStoredValue(contactUri, Contacts.PHOTO_THUMBNAIL_URI)); 4659 4660 assertInputStreamContent(loadTestPhoto(PhotoSize.DISPLAY_PHOTO), 4661 mResolver.openInputStream(photoUri)); 4662 assertInputStreamContent(loadTestPhoto(PhotoSize.THUMBNAIL), 4663 mResolver.openInputStream(photoThumbnailUri)); 4664 } 4665 4666 private static void assertInputStreamContent(byte[] expected, InputStream is) 4667 throws IOException { 4668 try { 4669 byte[] observed = new byte[expected.length]; 4670 int count = is.read(observed); 4671 assertEquals(expected.length, count); 4672 assertEquals(-1, is.read()); 4673 MoreAsserts.assertEquals(expected, observed); 4674 } finally { 4675 is.close(); 4676 } 4677 } 4678 4679 public void testSuperPrimaryPhoto() { 4680 long rawContactId1 = createRawContact(new Account("a", "a")); 4681 Uri photoUri1 = insertPhoto(rawContactId1, R.drawable.earth_normal); 4682 long photoId1 = ContentUris.parseId(photoUri1); 4683 4684 long rawContactId2 = createRawContact(new Account("b", "b")); 4685 Uri photoUri2 = insertPhoto(rawContactId2, R.drawable.earth_normal); 4686 long photoId2 = ContentUris.parseId(photoUri2); 4687 4688 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 4689 rawContactId1, rawContactId2); 4690 4691 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 4692 queryContactId(rawContactId1)); 4693 4694 long photoFileId1 = getStoredLongValue(Data.CONTENT_URI, Data._ID + "=?", 4695 new String[]{String.valueOf(photoId1)}, Photo.PHOTO_FILE_ID); 4696 String photoUri = ContentUris.withAppendedId(DisplayPhoto.CONTENT_URI, photoFileId1) 4697 .toString(); 4698 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1); 4699 assertStoredValue(contactUri, Contacts.PHOTO_URI, photoUri); 4700 4701 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 4702 rawContactId1, rawContactId2); 4703 4704 ContentValues values = new ContentValues(); 4705 values.put(Data.IS_SUPER_PRIMARY, 1); 4706 mResolver.update(photoUri2, values, null, null); 4707 4708 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 4709 rawContactId1, rawContactId2); 4710 contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 4711 queryContactId(rawContactId1)); 4712 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId2); 4713 4714 mResolver.update(photoUri1, values, null, null); 4715 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1); 4716 } 4717 4718 public void testUpdatePhoto() { 4719 ContentValues values = new ContentValues(); 4720 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 4721 long rawContactId = ContentUris.parseId(rawContactUri); 4722 insertStructuredName(rawContactId, "John", "Doe"); 4723 4724 Uri twigUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, 4725 queryContactId(rawContactId)), Contacts.Photo.CONTENT_DIRECTORY); 4726 4727 values.clear(); 4728 values.put(Data.RAW_CONTACT_ID, rawContactId); 4729 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 4730 values.putNull(Photo.PHOTO); 4731 Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 4732 long photoId = ContentUris.parseId(dataUri); 4733 4734 assertEquals(0, getCount(twigUri, null, null)); 4735 4736 values.clear(); 4737 values.put(Photo.PHOTO, loadTestPhoto()); 4738 mResolver.update(dataUri, values, null, null); 4739 assertNetworkNotified(true); 4740 4741 long twigId = getStoredLongValue(twigUri, Data._ID); 4742 assertEquals(photoId, twigId); 4743 } 4744 4745 public void testUpdateRawContactDataPhoto() { 4746 // setup a contact with a null photo 4747 ContentValues values = new ContentValues(); 4748 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 4749 long rawContactId = ContentUris.parseId(rawContactUri); 4750 4751 // setup a photo 4752 values.put(Data.RAW_CONTACT_ID, rawContactId); 4753 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 4754 values.putNull(Photo.PHOTO); 4755 4756 // try to do an update before insert should return count == 0 4757 Uri dataUri = Uri.withAppendedPath( 4758 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 4759 RawContacts.Data.CONTENT_DIRECTORY); 4760 assertEquals(0, mResolver.update(dataUri, values, Data.MIMETYPE + "=?", 4761 new String[] {Photo.CONTENT_ITEM_TYPE})); 4762 4763 mResolver.insert(Data.CONTENT_URI, values); 4764 4765 // save a photo to the db 4766 values.clear(); 4767 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 4768 values.put(Photo.PHOTO, loadTestPhoto()); 4769 assertEquals(1, mResolver.update(dataUri, values, Data.MIMETYPE + "=?", 4770 new String[] {Photo.CONTENT_ITEM_TYPE})); 4771 4772 // verify the photo 4773 Cursor storedPhoto = mResolver.query(dataUri, new String[] {Photo.PHOTO}, 4774 Data.MIMETYPE + "=?", new String[] {Photo.CONTENT_ITEM_TYPE}, null); 4775 storedPhoto.moveToFirst(); 4776 MoreAsserts.assertEquals(loadTestPhoto(PhotoSize.THUMBNAIL), storedPhoto.getBlob(0)); 4777 storedPhoto.close(); 4778 } 4779 4780 public void testOpenDisplayPhotoForContactId() throws IOException { 4781 long rawContactId = createRawContactWithName(); 4782 long contactId = queryContactId(rawContactId); 4783 insertPhoto(rawContactId, R.drawable.earth_normal); 4784 Uri photoUri = Contacts.CONTENT_URI.buildUpon() 4785 .appendPath(String.valueOf(contactId)) 4786 .appendPath(Contacts.Photo.DISPLAY_PHOTO).build(); 4787 assertInputStreamContent( 4788 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO), 4789 mResolver.openInputStream(photoUri)); 4790 } 4791 4792 public void testOpenDisplayPhotoForContactLookupKey() throws IOException { 4793 long rawContactId = createRawContactWithName(); 4794 long contactId = queryContactId(rawContactId); 4795 String lookupKey = queryLookupKey(contactId); 4796 insertPhoto(rawContactId, R.drawable.earth_normal); 4797 Uri photoUri = Contacts.CONTENT_LOOKUP_URI.buildUpon() 4798 .appendPath(lookupKey) 4799 .appendPath(Contacts.Photo.DISPLAY_PHOTO).build(); 4800 assertInputStreamContent( 4801 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO), 4802 mResolver.openInputStream(photoUri)); 4803 } 4804 4805 public void testOpenDisplayPhotoForContactLookupKeyAndId() throws IOException { 4806 long rawContactId = createRawContactWithName(); 4807 long contactId = queryContactId(rawContactId); 4808 String lookupKey = queryLookupKey(contactId); 4809 insertPhoto(rawContactId, R.drawable.earth_normal); 4810 Uri photoUri = Contacts.CONTENT_LOOKUP_URI.buildUpon() 4811 .appendPath(lookupKey) 4812 .appendPath(String.valueOf(contactId)) 4813 .appendPath(Contacts.Photo.DISPLAY_PHOTO).build(); 4814 assertInputStreamContent( 4815 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO), 4816 mResolver.openInputStream(photoUri)); 4817 } 4818 4819 public void testOpenDisplayPhotoForRawContactId() throws IOException { 4820 long rawContactId = createRawContactWithName(); 4821 insertPhoto(rawContactId, R.drawable.earth_normal); 4822 Uri photoUri = RawContacts.CONTENT_URI.buildUpon() 4823 .appendPath(String.valueOf(rawContactId)) 4824 .appendPath(RawContacts.DisplayPhoto.CONTENT_DIRECTORY).build(); 4825 assertInputStreamContent( 4826 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO), 4827 mResolver.openInputStream(photoUri)); 4828 } 4829 4830 public void testOpenDisplayPhotoByPhotoUri() throws IOException { 4831 long rawContactId = createRawContactWithName(); 4832 long contactId = queryContactId(rawContactId); 4833 insertPhoto(rawContactId, R.drawable.earth_normal); 4834 4835 // Get the photo URI out and check the content. 4836 String photoUri = getStoredValue( 4837 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 4838 Contacts.PHOTO_URI); 4839 assertInputStreamContent( 4840 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO), 4841 mResolver.openInputStream(Uri.parse(photoUri))); 4842 } 4843 4844 public void testPhotoUriForDisplayPhoto() { 4845 long rawContactId = createRawContactWithName(); 4846 long contactId = queryContactId(rawContactId); 4847 4848 // Photo being inserted is larger than a thumbnail, so it will be stored as a file. 4849 long dataId = ContentUris.parseId(insertPhoto(rawContactId, R.drawable.earth_normal)); 4850 String photoFileId = getStoredValue(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), 4851 Photo.PHOTO_FILE_ID); 4852 String photoUri = getStoredValue( 4853 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 4854 Contacts.PHOTO_URI); 4855 4856 // Check that the photo URI differs from the thumbnail. 4857 String thumbnailUri = getStoredValue( 4858 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 4859 Contacts.PHOTO_THUMBNAIL_URI); 4860 assertFalse(photoUri.equals(thumbnailUri)); 4861 4862 // URI should be of the form display_photo/ID 4863 assertEquals(Uri.withAppendedPath(DisplayPhoto.CONTENT_URI, photoFileId).toString(), 4864 photoUri); 4865 } 4866 4867 public void testPhotoUriForThumbnailPhoto() throws IOException { 4868 long rawContactId = createRawContactWithName(); 4869 long contactId = queryContactId(rawContactId); 4870 4871 // Photo being inserted is a thumbnail, so it will only be stored in a BLOB. The photo URI 4872 // will fall back to the thumbnail URI. 4873 insertPhoto(rawContactId, R.drawable.earth_small); 4874 String photoUri = getStoredValue( 4875 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 4876 Contacts.PHOTO_URI); 4877 4878 // Check that the photo URI is equal to the thumbnail URI. 4879 String thumbnailUri = getStoredValue( 4880 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 4881 Contacts.PHOTO_THUMBNAIL_URI); 4882 assertEquals(photoUri, thumbnailUri); 4883 4884 // URI should be of the form contacts/ID/photo 4885 assertEquals(Uri.withAppendedPath( 4886 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 4887 Contacts.Photo.CONTENT_DIRECTORY).toString(), 4888 photoUri); 4889 4890 // Loading the photo URI content should get the thumbnail. 4891 assertInputStreamContent( 4892 loadPhotoFromResource(R.drawable.earth_small, PhotoSize.THUMBNAIL), 4893 mResolver.openInputStream(Uri.parse(photoUri))); 4894 } 4895 4896 public void testWriteNewPhotoToAssetFile() throws Exception { 4897 long rawContactId = createRawContactWithName(); 4898 long contactId = queryContactId(rawContactId); 4899 4900 // Load in a huge photo. 4901 final byte[] originalPhoto = loadPhotoFromResource( 4902 R.drawable.earth_huge, PhotoSize.ORIGINAL); 4903 4904 // Write it out. 4905 final Uri writeablePhotoUri = RawContacts.CONTENT_URI.buildUpon() 4906 .appendPath(String.valueOf(rawContactId)) 4907 .appendPath(RawContacts.DisplayPhoto.CONTENT_DIRECTORY).build(); 4908 writePhotoAsync(writeablePhotoUri, originalPhoto); 4909 4910 // Check that the display photo and thumbnail have been set. 4911 String photoUri = null; 4912 for (int i = 0; i < 10 && photoUri == null; i++) { 4913 // Wait a tick for the photo processing to occur. 4914 Thread.sleep(100); 4915 photoUri = getStoredValue( 4916 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 4917 Contacts.PHOTO_URI); 4918 } 4919 4920 assertFalse(TextUtils.isEmpty(photoUri)); 4921 String thumbnailUri = getStoredValue( 4922 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 4923 Contacts.PHOTO_THUMBNAIL_URI); 4924 assertFalse(TextUtils.isEmpty(thumbnailUri)); 4925 assertNotSame(photoUri, thumbnailUri); 4926 4927 // Check the content of the display photo and thumbnail. 4928 assertInputStreamContent( 4929 loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.DISPLAY_PHOTO), 4930 mResolver.openInputStream(Uri.parse(photoUri))); 4931 assertInputStreamContent( 4932 loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.THUMBNAIL), 4933 mResolver.openInputStream(Uri.parse(thumbnailUri))); 4934 } 4935 4936 public void testWriteUpdatedPhotoToAssetFile() throws Exception { 4937 long rawContactId = createRawContactWithName(); 4938 long contactId = queryContactId(rawContactId); 4939 4940 // Insert a large photo first. 4941 insertPhoto(rawContactId, R.drawable.earth_large); 4942 String largeEarthPhotoUri = getStoredValue( 4943 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), Contacts.PHOTO_URI); 4944 4945 // Load in a huge photo. 4946 byte[] originalPhoto = loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.ORIGINAL); 4947 4948 // Write it out. 4949 Uri writeablePhotoUri = RawContacts.CONTENT_URI.buildUpon() 4950 .appendPath(String.valueOf(rawContactId)) 4951 .appendPath(RawContacts.DisplayPhoto.CONTENT_DIRECTORY).build(); 4952 writePhotoAsync(writeablePhotoUri, originalPhoto); 4953 4954 // Allow a second for processing to occur. 4955 Thread.sleep(1000); 4956 4957 // Check that the display photo URI has been modified. 4958 String hugeEarthPhotoUri = getStoredValue( 4959 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), Contacts.PHOTO_URI); 4960 assertFalse(hugeEarthPhotoUri.equals(largeEarthPhotoUri)); 4961 4962 // Check the content of the display photo and thumbnail. 4963 String hugeEarthThumbnailUri = getStoredValue( 4964 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 4965 Contacts.PHOTO_THUMBNAIL_URI); 4966 assertInputStreamContent( 4967 loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.DISPLAY_PHOTO), 4968 mResolver.openInputStream(Uri.parse(hugeEarthPhotoUri))); 4969 assertInputStreamContent( 4970 loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.THUMBNAIL), 4971 mResolver.openInputStream(Uri.parse(hugeEarthThumbnailUri))); 4972 4973 } 4974 4975 private void writePhotoAsync(final Uri uri, final byte[] photoBytes) throws Exception { 4976 AsyncTask<Object, Object, Object> task = new AsyncTask<Object, Object, Object>() { 4977 @Override 4978 protected Object doInBackground(Object... params) { 4979 OutputStream os; 4980 try { 4981 os = mResolver.openOutputStream(uri, "rw"); 4982 os.write(photoBytes); 4983 os.close(); 4984 return null; 4985 } catch (IOException ioe) { 4986 throw new RuntimeException(ioe); 4987 } 4988 } 4989 }; 4990 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[])null).get(); 4991 } 4992 4993 public void testPhotoDimensionLimits() { 4994 ContentValues values = new ContentValues(); 4995 values.put(DisplayPhoto.DISPLAY_MAX_DIM, 256); 4996 values.put(DisplayPhoto.THUMBNAIL_MAX_DIM, 96); 4997 assertStoredValues(DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI, values); 4998 } 4999 5000 public void testPhotoStoreCleanup() throws IOException { 5001 SynchronousContactsProvider2 provider = (SynchronousContactsProvider2) mActor.provider; 5002 PhotoStore photoStore = provider.getPhotoStore(); 5003 5004 // Trigger an initial cleanup so another one won't happen while we're running this test. 5005 provider.cleanupPhotoStore(); 5006 5007 // Insert a couple of contacts with photos. 5008 long rawContactId1 = createRawContactWithName(); 5009 long contactId1 = queryContactId(rawContactId1); 5010 long dataId1 = ContentUris.parseId(insertPhoto(rawContactId1, R.drawable.earth_normal)); 5011 long photoFileId1 = 5012 getStoredLongValue(ContentUris.withAppendedId(Data.CONTENT_URI, dataId1), 5013 Photo.PHOTO_FILE_ID); 5014 5015 long rawContactId2 = createRawContactWithName(); 5016 long contactId2 = queryContactId(rawContactId2); 5017 long dataId2 = ContentUris.parseId(insertPhoto(rawContactId2, R.drawable.earth_normal)); 5018 long photoFileId2 = 5019 getStoredLongValue(ContentUris.withAppendedId(Data.CONTENT_URI, dataId2), 5020 Photo.PHOTO_FILE_ID); 5021 5022 // Update the second raw contact with a different photo. 5023 ContentValues values = new ContentValues(); 5024 values.put(Data.RAW_CONTACT_ID, rawContactId2); 5025 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 5026 values.put(Photo.PHOTO, loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.ORIGINAL)); 5027 assertEquals(1, mResolver.update(Data.CONTENT_URI, values, Data._ID + "=?", 5028 new String[]{String.valueOf(dataId2)})); 5029 long replacementPhotoFileId = 5030 getStoredLongValue(ContentUris.withAppendedId(Data.CONTENT_URI, dataId2), 5031 Photo.PHOTO_FILE_ID); 5032 5033 // Insert a third raw contact that has a bogus photo file ID. 5034 long bogusFileId = 1234567; 5035 long rawContactId3 = createRawContactWithName(); 5036 long contactId3 = queryContactId(rawContactId3); 5037 values.clear(); 5038 values.put(Data.RAW_CONTACT_ID, rawContactId3); 5039 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 5040 values.put(Photo.PHOTO, loadPhotoFromResource(R.drawable.earth_normal, 5041 PhotoSize.THUMBNAIL)); 5042 values.put(Photo.PHOTO_FILE_ID, bogusFileId); 5043 values.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 5044 mResolver.insert(Data.CONTENT_URI, values); 5045 5046 // Insert a fourth raw contact with a stream item that has a photo, then remove that photo 5047 // from the photo store. 5048 Account socialAccount = new Account("social", "social"); 5049 long rawContactId4 = createRawContactWithName(socialAccount); 5050 Uri streamItemUri = 5051 insertStreamItem(rawContactId4, buildGenericStreamItemValues(), socialAccount); 5052 long streamItemId = ContentUris.parseId(streamItemUri); 5053 Uri streamItemPhotoUri = insertStreamItemPhoto( 5054 streamItemId, buildGenericStreamItemPhotoValues(0), socialAccount); 5055 long streamItemPhotoFileId = getStoredLongValue(streamItemPhotoUri, 5056 StreamItemPhotos.PHOTO_FILE_ID); 5057 photoStore.remove(streamItemPhotoFileId); 5058 5059 // Also insert a bogus photo that nobody is using. 5060 long bogusPhotoId = photoStore.insert(new PhotoProcessor(loadPhotoFromResource( 5061 R.drawable.earth_huge, PhotoSize.ORIGINAL), 256, 96)); 5062 5063 // Manually trigger another cleanup in the provider. 5064 provider.cleanupPhotoStore(); 5065 5066 // The following things should have happened. 5067 5068 // 1. Raw contact 1 and its photo remain unaffected. 5069 assertEquals(photoFileId1, (long) getStoredLongValue( 5070 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId1), 5071 Contacts.PHOTO_FILE_ID)); 5072 5073 // 2. Raw contact 2 retains its new photo. The old one is deleted from the photo store. 5074 assertEquals(replacementPhotoFileId, (long) getStoredLongValue( 5075 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId2), 5076 Contacts.PHOTO_FILE_ID)); 5077 assertNull(photoStore.get(photoFileId2)); 5078 5079 // 3. Raw contact 3 should have its photo file reference cleared. 5080 assertNull(getStoredValue( 5081 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId3), 5082 Contacts.PHOTO_FILE_ID)); 5083 5084 // 4. The bogus photo that nobody was using should be cleared from the photo store. 5085 assertNull(photoStore.get(bogusPhotoId)); 5086 5087 // 5. The bogus stream item photo should be cleared from the stream item. 5088 assertStoredValues(Uri.withAppendedPath( 5089 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 5090 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 5091 new ContentValues[0]); 5092 } 5093 5094 public void testOverwritePhotoWithThumbnail() throws IOException { 5095 long rawContactId = createRawContactWithName(); 5096 long contactId = queryContactId(rawContactId); 5097 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 5098 5099 // Write a regular-size photo. 5100 long dataId = ContentUris.parseId(insertPhoto(rawContactId, R.drawable.earth_normal)); 5101 Long photoFileId = getStoredLongValue(contactUri, Contacts.PHOTO_FILE_ID); 5102 assertTrue(photoFileId != null && photoFileId > 0); 5103 5104 // Now overwrite the photo with a thumbnail-sized photo. 5105 ContentValues update = new ContentValues(); 5106 update.put(Photo.PHOTO, loadPhotoFromResource(R.drawable.earth_small, PhotoSize.ORIGINAL)); 5107 mResolver.update(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), update, null, null); 5108 5109 // Photo file ID should have been nulled out, and the photo URI should be the same as the 5110 // thumbnail URI. 5111 assertNull(getStoredValue(contactUri, Contacts.PHOTO_FILE_ID)); 5112 String photoUri = getStoredValue(contactUri, Contacts.PHOTO_URI); 5113 String thumbnailUri = getStoredValue(contactUri, Contacts.PHOTO_THUMBNAIL_URI); 5114 assertEquals(photoUri, thumbnailUri); 5115 5116 // Retrieving the photo URI should get the thumbnail content. 5117 assertInputStreamContent(loadPhotoFromResource(R.drawable.earth_small, PhotoSize.THUMBNAIL), 5118 mResolver.openInputStream(Uri.parse(photoUri))); 5119 } 5120 5121 public void testUpdateRawContactSetStarred() { 5122 long rawContactId1 = createRawContactWithName(); 5123 Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 5124 long rawContactId2 = createRawContactWithName(); 5125 Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2); 5126 setAggregationException( 5127 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 5128 5129 long contactId = queryContactId(rawContactId1); 5130 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 5131 assertStoredValue(contactUri, Contacts.STARRED, "0"); 5132 5133 ContentValues values = new ContentValues(); 5134 values.put(RawContacts.STARRED, "1"); 5135 5136 mResolver.update(rawContactUri1, values, null, null); 5137 5138 assertStoredValue(rawContactUri1, RawContacts.STARRED, "1"); 5139 assertStoredValue(rawContactUri2, RawContacts.STARRED, "0"); 5140 assertStoredValue(contactUri, Contacts.STARRED, "1"); 5141 5142 values.put(RawContacts.STARRED, "0"); 5143 mResolver.update(rawContactUri1, values, null, null); 5144 5145 assertStoredValue(rawContactUri1, RawContacts.STARRED, "0"); 5146 assertStoredValue(rawContactUri2, RawContacts.STARRED, "0"); 5147 assertStoredValue(contactUri, Contacts.STARRED, "0"); 5148 5149 values.put(Contacts.STARRED, "1"); 5150 mResolver.update(contactUri, values, null, null); 5151 5152 assertStoredValue(rawContactUri1, RawContacts.STARRED, "1"); 5153 assertStoredValue(rawContactUri2, RawContacts.STARRED, "1"); 5154 assertStoredValue(contactUri, Contacts.STARRED, "1"); 5155 } 5156 5157 public void testSetAndClearSuperPrimaryEmail() { 5158 long rawContactId1 = createRawContact(new Account("a", "a")); 5159 Uri mailUri11 = insertEmail(rawContactId1, "test1@domain1.com"); 5160 Uri mailUri12 = insertEmail(rawContactId1, "test2@domain1.com"); 5161 5162 long rawContactId2 = createRawContact(new Account("b", "b")); 5163 Uri mailUri21 = insertEmail(rawContactId2, "test1@domain2.com"); 5164 Uri mailUri22 = insertEmail(rawContactId2, "test2@domain2.com"); 5165 5166 assertStoredValue(mailUri11, Data.IS_PRIMARY, 0); 5167 assertStoredValue(mailUri11, Data.IS_SUPER_PRIMARY, 0); 5168 assertStoredValue(mailUri12, Data.IS_PRIMARY, 0); 5169 assertStoredValue(mailUri12, Data.IS_SUPER_PRIMARY, 0); 5170 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 5171 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 5172 assertStoredValue(mailUri22, Data.IS_PRIMARY, 0); 5173 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 0); 5174 5175 // Set super primary on the first pair, primary on the second 5176 { 5177 ContentValues values = new ContentValues(); 5178 values.put(Data.IS_SUPER_PRIMARY, 1); 5179 mResolver.update(mailUri11, values, null, null); 5180 } 5181 { 5182 ContentValues values = new ContentValues(); 5183 values.put(Data.IS_SUPER_PRIMARY, 1); 5184 mResolver.update(mailUri22, values, null, null); 5185 } 5186 5187 assertStoredValue(mailUri11, Data.IS_PRIMARY, 1); 5188 assertStoredValue(mailUri11, Data.IS_SUPER_PRIMARY, 1); 5189 assertStoredValue(mailUri12, Data.IS_PRIMARY, 0); 5190 assertStoredValue(mailUri12, Data.IS_SUPER_PRIMARY, 0); 5191 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 5192 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 5193 assertStoredValue(mailUri22, Data.IS_PRIMARY, 1); 5194 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 1); 5195 5196 // Clear primary on the first pair, make sure second is not affected and super_primary is 5197 // also cleared 5198 { 5199 ContentValues values = new ContentValues(); 5200 values.put(Data.IS_PRIMARY, 0); 5201 mResolver.update(mailUri11, values, null, null); 5202 } 5203 5204 assertStoredValue(mailUri11, Data.IS_PRIMARY, 0); 5205 assertStoredValue(mailUri11, Data.IS_SUPER_PRIMARY, 0); 5206 assertStoredValue(mailUri12, Data.IS_PRIMARY, 0); 5207 assertStoredValue(mailUri12, Data.IS_SUPER_PRIMARY, 0); 5208 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 5209 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 5210 assertStoredValue(mailUri22, Data.IS_PRIMARY, 1); 5211 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 1); 5212 5213 // Ensure that we can only clear super_primary, if we specify the correct data row 5214 { 5215 ContentValues values = new ContentValues(); 5216 values.put(Data.IS_SUPER_PRIMARY, 0); 5217 mResolver.update(mailUri21, values, null, null); 5218 } 5219 5220 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 5221 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 5222 assertStoredValue(mailUri22, Data.IS_PRIMARY, 1); 5223 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 1); 5224 5225 // Ensure that we can only clear primary, if we specify the correct data row 5226 { 5227 ContentValues values = new ContentValues(); 5228 values.put(Data.IS_PRIMARY, 0); 5229 mResolver.update(mailUri21, values, null, null); 5230 } 5231 5232 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 5233 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 5234 assertStoredValue(mailUri22, Data.IS_PRIMARY, 1); 5235 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 1); 5236 5237 // Now clear super-primary for real 5238 { 5239 ContentValues values = new ContentValues(); 5240 values.put(Data.IS_SUPER_PRIMARY, 0); 5241 mResolver.update(mailUri22, values, null, null); 5242 } 5243 5244 assertStoredValue(mailUri11, Data.IS_PRIMARY, 0); 5245 assertStoredValue(mailUri11, Data.IS_SUPER_PRIMARY, 0); 5246 assertStoredValue(mailUri12, Data.IS_PRIMARY, 0); 5247 assertStoredValue(mailUri12, Data.IS_SUPER_PRIMARY, 0); 5248 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 5249 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 5250 assertStoredValue(mailUri22, Data.IS_PRIMARY, 1); 5251 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 0); 5252 } 5253 5254 /** 5255 * Common function for the testNewPrimaryIn* functions. Its four configurations 5256 * are each called from its own test 5257 */ 5258 public void testChangingPrimary(boolean inUpdate, boolean withSuperPrimary) { 5259 long rawContactId = createRawContact(new Account("a", "a")); 5260 Uri mailUri1 = insertEmail(rawContactId, "test1@domain1.com", true); 5261 5262 if (withSuperPrimary) { 5263 final ContentValues values = new ContentValues(); 5264 values.put(Data.IS_SUPER_PRIMARY, 1); 5265 mResolver.update(mailUri1, values, null, null); 5266 } 5267 5268 assertStoredValue(mailUri1, Data.IS_PRIMARY, 1); 5269 assertStoredValue(mailUri1, Data.IS_SUPER_PRIMARY, withSuperPrimary ? 1 : 0); 5270 5271 // Insert another item 5272 final Uri mailUri2; 5273 if (inUpdate) { 5274 mailUri2 = insertEmail(rawContactId, "test2@domain1.com"); 5275 5276 assertStoredValue(mailUri1, Data.IS_PRIMARY, 1); 5277 assertStoredValue(mailUri1, Data.IS_SUPER_PRIMARY, withSuperPrimary ? 1 : 0); 5278 assertStoredValue(mailUri2, Data.IS_PRIMARY, 0); 5279 assertStoredValue(mailUri2, Data.IS_SUPER_PRIMARY, 0); 5280 5281 final ContentValues values = new ContentValues(); 5282 values.put(Data.IS_PRIMARY, 1); 5283 mResolver.update(mailUri2, values, null, null); 5284 } else { 5285 // directly add as default 5286 mailUri2 = insertEmail(rawContactId, "test2@domain1.com", true); 5287 } 5288 5289 // Ensure that primary has been unset on the first 5290 // If withSuperPrimary is set, also ensure that is has been moved to the new item 5291 assertStoredValue(mailUri1, Data.IS_PRIMARY, 0); 5292 assertStoredValue(mailUri1, Data.IS_SUPER_PRIMARY, 0); 5293 assertStoredValue(mailUri2, Data.IS_PRIMARY, 1); 5294 assertStoredValue(mailUri2, Data.IS_SUPER_PRIMARY, withSuperPrimary ? 1 : 0); 5295 } 5296 5297 public void testNewPrimaryInInsert() { 5298 testChangingPrimary(false, false); 5299 } 5300 5301 public void testNewPrimaryInInsertWithSuperPrimary() { 5302 testChangingPrimary(false, true); 5303 } 5304 5305 public void testNewPrimaryInUpdate() { 5306 testChangingPrimary(true, false); 5307 } 5308 5309 public void testNewPrimaryInUpdateWithSuperPrimary() { 5310 testChangingPrimary(true, true); 5311 } 5312 5313 public void testLiveFolders() { 5314 long rawContactId1 = createRawContactWithName("James", "Sullivan"); 5315 insertPhoneNumber(rawContactId1, "5234567890"); 5316 long contactId1 = queryContactId(rawContactId1); 5317 5318 long rawContactId2 = createRawContactWithName("Mike", "Wazowski"); 5319 long contactId2 = queryContactId(rawContactId2); 5320 storeValue(Contacts.CONTENT_URI, contactId2, Contacts.STARRED, "1"); 5321 5322 long rawContactId3 = createRawContactWithName("Randall", "Boggs"); 5323 long contactId3 = queryContactId(rawContactId3); 5324 long groupId = createGroup(NO_ACCOUNT, "src1", "VIP"); 5325 insertGroupMembership(rawContactId3, groupId); 5326 5327 assertLiveFolderContents( 5328 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 5329 "live_folders/contacts"), 5330 contactId1, "James Sullivan", 5331 contactId2, "Mike Wazowski", 5332 contactId3, "Randall Boggs"); 5333 5334 assertLiveFolderContents( 5335 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 5336 "live_folders/contacts_with_phones"), 5337 contactId1, "James Sullivan"); 5338 5339 assertLiveFolderContents( 5340 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 5341 "live_folders/favorites"), 5342 contactId2, "Mike Wazowski"); 5343 5344 assertLiveFolderContents( 5345 Uri.withAppendedPath(Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 5346 "live_folders/contacts"), Uri.encode("VIP")), 5347 contactId3, "Randall Boggs"); 5348 } 5349 5350 private void assertLiveFolderContents(Uri uri, Object... expected) { 5351 Cursor c = mResolver.query(uri, new String[]{LiveFolders._ID, LiveFolders.NAME}, 5352 null, null, LiveFolders._ID); 5353 assertEquals(expected.length/2, c.getCount()); 5354 for (int i = 0; i < expected.length/2; i++) { 5355 assertTrue(c.moveToNext()); 5356 assertEquals(((Long)expected[i * 2]).longValue(), c.getLong(0)); 5357 assertEquals(expected[i * 2 + 1], c.getString(1)); 5358 } 5359 c.close(); 5360 } 5361 5362 public void testContactCounts() { 5363 Uri uri = Contacts.CONTENT_URI.buildUpon() 5364 .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build(); 5365 5366 createRawContact(); 5367 createRawContactWithName("James", "Sullivan"); 5368 createRawContactWithName("The Abominable", "Snowman"); 5369 createRawContactWithName("Mike", "Wazowski"); 5370 createRawContactWithName("randall", "boggs"); 5371 createRawContactWithName("Boo", null); 5372 createRawContactWithName("Mary", null); 5373 createRawContactWithName("Roz", null); 5374 5375 Cursor cursor = mResolver.query(uri, 5376 new String[]{Contacts.DISPLAY_NAME}, 5377 null, null, Contacts.SORT_KEY_PRIMARY + " COLLATE LOCALIZED"); 5378 5379 assertFirstLetterValues(cursor, null, "B", "J", "M", "R", "T"); 5380 assertFirstLetterCounts(cursor, 1, 1, 1, 2, 2, 1); 5381 cursor.close(); 5382 5383 cursor = mResolver.query(uri, 5384 new String[]{Contacts.DISPLAY_NAME}, 5385 null, null, Contacts.SORT_KEY_ALTERNATIVE + " COLLATE LOCALIZED DESC"); 5386 5387 assertFirstLetterValues(cursor, "W", "S", "R", "M", "B", null); 5388 assertFirstLetterCounts(cursor, 1, 2, 1, 1, 2, 1); 5389 cursor.close(); 5390 } 5391 5392 private void assertFirstLetterValues(Cursor cursor, String... expected) { 5393 String[] actual = cursor.getExtras() 5394 .getStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES); 5395 MoreAsserts.assertEquals(expected, actual); 5396 } 5397 5398 private void assertFirstLetterCounts(Cursor cursor, int... expected) { 5399 int[] actual = cursor.getExtras() 5400 .getIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS); 5401 MoreAsserts.assertEquals(expected, actual); 5402 } 5403 5404 public void testReadBooleanQueryParameter() { 5405 assertBooleanUriParameter("foo:bar", "bool", true, true); 5406 assertBooleanUriParameter("foo:bar", "bool", false, false); 5407 assertBooleanUriParameter("foo:bar?bool=0", "bool", true, false); 5408 assertBooleanUriParameter("foo:bar?bool=1", "bool", false, true); 5409 assertBooleanUriParameter("foo:bar?bool=false", "bool", true, false); 5410 assertBooleanUriParameter("foo:bar?bool=true", "bool", false, true); 5411 assertBooleanUriParameter("foo:bar?bool=FaLsE", "bool", true, false); 5412 assertBooleanUriParameter("foo:bar?bool=false&some=some", "bool", true, false); 5413 assertBooleanUriParameter("foo:bar?bool=1&some=some", "bool", false, true); 5414 assertBooleanUriParameter("foo:bar?some=bool", "bool", true, true); 5415 assertBooleanUriParameter("foo:bar?bool", "bool", true, true); 5416 } 5417 5418 private void assertBooleanUriParameter(String uriString, String parameter, 5419 boolean defaultValue, boolean expectedValue) { 5420 assertEquals(expectedValue, ContactsProvider2.readBooleanQueryParameter( 5421 Uri.parse(uriString), parameter, defaultValue)); 5422 } 5423 5424 public void testGetQueryParameter() { 5425 assertQueryParameter("foo:bar", "param", null); 5426 assertQueryParameter("foo:bar?param", "param", null); 5427 assertQueryParameter("foo:bar?param=", "param", ""); 5428 assertQueryParameter("foo:bar?param=val", "param", "val"); 5429 assertQueryParameter("foo:bar?param=val&some=some", "param", "val"); 5430 assertQueryParameter("foo:bar?some=some¶m=val", "param", "val"); 5431 assertQueryParameter("foo:bar?some=some¶m=val&else=else", "param", "val"); 5432 assertQueryParameter("foo:bar?param=john%40doe.com", "param", "john@doe.com"); 5433 assertQueryParameter("foo:bar?some_param=val", "param", null); 5434 assertQueryParameter("foo:bar?some_param=val1¶m=val2", "param", "val2"); 5435 assertQueryParameter("foo:bar?some_param=val1¶m=", "param", ""); 5436 assertQueryParameter("foo:bar?some_param=val1¶m", "param", null); 5437 assertQueryParameter("foo:bar?some_param=val1&another_param=val2¶m=val3", 5438 "param", "val3"); 5439 assertQueryParameter("foo:bar?some_param=val1¶m=val2&some_param=val3", 5440 "param", "val2"); 5441 assertQueryParameter("foo:bar?param=val1&some_param=val2", "param", "val1"); 5442 assertQueryParameter("foo:bar?p=val1&pp=val2", "p", "val1"); 5443 assertQueryParameter("foo:bar?pp=val1&p=val2", "p", "val2"); 5444 assertQueryParameter("foo:bar?ppp=val1&pp=val2&p=val3", "p", "val3"); 5445 assertQueryParameter("foo:bar?ppp=val&", "p", null); 5446 } 5447 5448 public void testMissingAccountTypeParameter() { 5449 // Try querying for RawContacts only using ACCOUNT_NAME 5450 final Uri queryUri = RawContacts.CONTENT_URI.buildUpon().appendQueryParameter( 5451 RawContacts.ACCOUNT_NAME, "lolwut").build(); 5452 try { 5453 final Cursor cursor = mResolver.query(queryUri, null, null, null, null); 5454 fail("Able to query with incomplete account query parameters"); 5455 } catch (IllegalArgumentException e) { 5456 // Expected behavior. 5457 } 5458 } 5459 5460 public void testInsertInconsistentAccountType() { 5461 // Try inserting RawContact with inconsistent Accounts 5462 final Account red = new Account("red", "red"); 5463 final Account blue = new Account("blue", "blue"); 5464 5465 final ContentValues values = new ContentValues(); 5466 values.put(RawContacts.ACCOUNT_NAME, red.name); 5467 values.put(RawContacts.ACCOUNT_TYPE, red.type); 5468 5469 final Uri insertUri = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, blue); 5470 try { 5471 mResolver.insert(insertUri, values); 5472 fail("Able to insert RawContact with inconsistent account details"); 5473 } catch (IllegalArgumentException e) { 5474 // Expected behavior. 5475 } 5476 } 5477 5478 public void testProviderStatusNoContactsNoAccounts() throws Exception { 5479 assertProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 5480 } 5481 5482 public void testProviderStatusOnlyLocalContacts() throws Exception { 5483 long rawContactId = createRawContact(); 5484 assertProviderStatus(ProviderStatus.STATUS_NORMAL); 5485 mResolver.delete( 5486 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), null, null); 5487 assertProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 5488 } 5489 5490 public void testProviderStatusWithAccounts() throws Exception { 5491 assertProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 5492 mActor.setAccounts(new Account[]{ACCOUNT_1}); 5493 ((ContactsProvider2)getProvider()).onAccountsUpdated(new Account[]{ACCOUNT_1}); 5494 assertProviderStatus(ProviderStatus.STATUS_NORMAL); 5495 mActor.setAccounts(new Account[0]); 5496 ((ContactsProvider2)getProvider()).onAccountsUpdated(new Account[0]); 5497 assertProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 5498 } 5499 5500 private void assertProviderStatus(int expectedProviderStatus) { 5501 Cursor cursor = mResolver.query(ProviderStatus.CONTENT_URI, 5502 new String[]{ProviderStatus.DATA1, ProviderStatus.STATUS}, null, null, null); 5503 assertTrue(cursor.moveToFirst()); 5504 assertEquals(0, cursor.getLong(0)); 5505 assertEquals(expectedProviderStatus, cursor.getInt(1)); 5506 cursor.close(); 5507 } 5508 5509 public void testProperties() throws Exception { 5510 ContactsProvider2 provider = (ContactsProvider2)getProvider(); 5511 ContactsDatabaseHelper helper = (ContactsDatabaseHelper)provider.getDatabaseHelper(); 5512 assertNull(helper.getProperty("non-existent", null)); 5513 assertEquals("default", helper.getProperty("non-existent", "default")); 5514 5515 helper.setProperty("existent1", "string1"); 5516 helper.setProperty("existent2", "string2"); 5517 assertEquals("string1", helper.getProperty("existent1", "default")); 5518 assertEquals("string2", helper.getProperty("existent2", "default")); 5519 helper.setProperty("existent1", null); 5520 assertEquals("default", helper.getProperty("existent1", "default")); 5521 } 5522 5523 private class VCardTestUriCreator { 5524 private String mLookup1; 5525 private String mLookup2; 5526 5527 public VCardTestUriCreator(String lookup1, String lookup2) { 5528 super(); 5529 mLookup1 = lookup1; 5530 mLookup2 = lookup2; 5531 } 5532 5533 public Uri getUri1() { 5534 return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup1); 5535 } 5536 5537 public Uri getUri2() { 5538 return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup2); 5539 } 5540 5541 public Uri getCombinedUri() { 5542 return Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI, 5543 Uri.encode(mLookup1 + ":" + mLookup2)); 5544 } 5545 } 5546 5547 private VCardTestUriCreator createVCardTestContacts() { 5548 final long rawContactId1 = createRawContact(mAccount, RawContacts.SOURCE_ID, "4:12"); 5549 insertStructuredName(rawContactId1, "John", "Doe"); 5550 5551 final long rawContactId2 = createRawContact(mAccount, RawContacts.SOURCE_ID, "3:4%121"); 5552 insertStructuredName(rawContactId2, "Jane", "Doh"); 5553 5554 final long contactId1 = queryContactId(rawContactId1); 5555 final long contactId2 = queryContactId(rawContactId2); 5556 final Uri contact1Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId1); 5557 final Uri contact2Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId2); 5558 final String lookup1 = 5559 Uri.encode(Contacts.getLookupUri(mResolver, contact1Uri).getPathSegments().get(2)); 5560 final String lookup2 = 5561 Uri.encode(Contacts.getLookupUri(mResolver, contact2Uri).getPathSegments().get(2)); 5562 return new VCardTestUriCreator(lookup1, lookup2); 5563 } 5564 5565 public void testQueryMultiVCard() { 5566 // No need to create any contacts here, because the query for multiple vcards 5567 // does not go into the database at all 5568 Uri uri = Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI, Uri.encode("123:456")); 5569 Cursor cursor = mResolver.query(uri, null, null, null, null); 5570 assertEquals(1, cursor.getCount()); 5571 assertTrue(cursor.moveToFirst()); 5572 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 5573 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 5574 5575 // The resulting name contains date and time. Ensure that before and after are correct 5576 assertTrue(filename.startsWith("vcards_")); 5577 assertTrue(filename.endsWith(".vcf")); 5578 cursor.close(); 5579 } 5580 5581 public void testQueryFileSingleVCard() { 5582 final VCardTestUriCreator contacts = createVCardTestContacts(); 5583 5584 { 5585 Cursor cursor = mResolver.query(contacts.getUri1(), null, null, null, null); 5586 assertEquals(1, cursor.getCount()); 5587 assertTrue(cursor.moveToFirst()); 5588 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 5589 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 5590 assertEquals("John Doe.vcf", filename); 5591 cursor.close(); 5592 } 5593 5594 { 5595 Cursor cursor = mResolver.query(contacts.getUri2(), null, null, null, null); 5596 assertEquals(1, cursor.getCount()); 5597 assertTrue(cursor.moveToFirst()); 5598 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 5599 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 5600 assertEquals("Jane Doh.vcf", filename); 5601 cursor.close(); 5602 } 5603 } 5604 5605 public void testQueryFileProfileVCard() { 5606 createBasicProfileContact(new ContentValues()); 5607 Cursor cursor = mResolver.query(Profile.CONTENT_VCARD_URI, null, null, null, null); 5608 assertEquals(1, cursor.getCount()); 5609 assertTrue(cursor.moveToFirst()); 5610 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 5611 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 5612 assertEquals("Mia Prophyl.vcf", filename); 5613 cursor.close(); 5614 } 5615 5616 public void testOpenAssetFileMultiVCard() throws IOException { 5617 final VCardTestUriCreator contacts = createVCardTestContacts(); 5618 5619 final AssetFileDescriptor descriptor = 5620 mResolver.openAssetFileDescriptor(contacts.getCombinedUri(), "r"); 5621 final FileInputStream inputStream = descriptor.createInputStream(); 5622 String data = readToEnd(inputStream); 5623 inputStream.close(); 5624 descriptor.close(); 5625 5626 // Ensure that the resulting VCard has both contacts 5627 assertTrue(data.contains("N:Doe;John;;;")); 5628 assertTrue(data.contains("N:Doh;Jane;;;")); 5629 } 5630 5631 public void testOpenAssetFileSingleVCard() throws IOException { 5632 final VCardTestUriCreator contacts = createVCardTestContacts(); 5633 5634 // Ensure that the right VCard is being created in each case 5635 { 5636 final AssetFileDescriptor descriptor = 5637 mResolver.openAssetFileDescriptor(contacts.getUri1(), "r"); 5638 final FileInputStream inputStream = descriptor.createInputStream(); 5639 final String data = readToEnd(inputStream); 5640 inputStream.close(); 5641 descriptor.close(); 5642 5643 assertTrue(data.contains("N:Doe;John;;;")); 5644 assertFalse(data.contains("N:Doh;Jane;;;")); 5645 } 5646 5647 { 5648 final AssetFileDescriptor descriptor = 5649 mResolver.openAssetFileDescriptor(contacts.getUri2(), "r"); 5650 final FileInputStream inputStream = descriptor.createInputStream(); 5651 final String data = readToEnd(inputStream); 5652 inputStream.close(); 5653 descriptor.close(); 5654 5655 assertFalse(data.contains("N:Doe;John;;;")); 5656 assertTrue(data.contains("N:Doh;Jane;;;")); 5657 } 5658 } 5659 5660 public void testAutoGroupMembership() { 5661 long g1 = createGroup(mAccount, "g1", "t1", 0, true /* autoAdd */, false /* favorite */); 5662 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 5663 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, true /* autoAdd */, false /* favorite */); 5664 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, false/* favorite */); 5665 long r1 = createRawContact(mAccount); 5666 long r2 = createRawContact(mAccountTwo); 5667 long r3 = createRawContact(null); 5668 5669 Cursor c = queryGroupMemberships(mAccount); 5670 try { 5671 assertTrue(c.moveToNext()); 5672 assertEquals(g1, c.getLong(0)); 5673 assertEquals(r1, c.getLong(1)); 5674 assertFalse(c.moveToNext()); 5675 } finally { 5676 c.close(); 5677 } 5678 5679 c = queryGroupMemberships(mAccountTwo); 5680 try { 5681 assertTrue(c.moveToNext()); 5682 assertEquals(g3, c.getLong(0)); 5683 assertEquals(r2, c.getLong(1)); 5684 assertFalse(c.moveToNext()); 5685 } finally { 5686 c.close(); 5687 } 5688 } 5689 5690 public void testNoAutoAddMembershipAfterGroupCreation() { 5691 long r1 = createRawContact(mAccount); 5692 long r2 = createRawContact(mAccount); 5693 long r3 = createRawContact(mAccount); 5694 long r4 = createRawContact(mAccountTwo); 5695 long r5 = createRawContact(mAccountTwo); 5696 long r6 = createRawContact(null); 5697 5698 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 5699 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5700 5701 long g1 = createGroup(mAccount, "g1", "t1", 0, true /* autoAdd */, false /* favorite */); 5702 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 5703 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, true /* autoAdd */, false/* favorite */); 5704 5705 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 5706 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5707 } 5708 5709 // create some starred and non-starred contacts, some associated with account, some not 5710 // favorites group created 5711 // the starred contacts should be added to group 5712 // favorites group removed 5713 // no change to starred status 5714 public void testFavoritesMembershipAfterGroupCreation() { 5715 long r1 = createRawContact(mAccount, RawContacts.STARRED, "1"); 5716 long r2 = createRawContact(mAccount); 5717 long r3 = createRawContact(mAccount, RawContacts.STARRED, "1"); 5718 long r4 = createRawContact(mAccountTwo, RawContacts.STARRED, "1"); 5719 long r5 = createRawContact(mAccountTwo); 5720 long r6 = createRawContact(null, RawContacts.STARRED, "1"); 5721 long r7 = createRawContact(null); 5722 5723 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 5724 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5725 5726 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 5727 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 5728 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, false /* autoAdd */, false/* favorite */); 5729 5730 assertTrue(queryRawContactIsStarred(r1)); 5731 assertFalse(queryRawContactIsStarred(r2)); 5732 assertTrue(queryRawContactIsStarred(r3)); 5733 assertTrue(queryRawContactIsStarred(r4)); 5734 assertFalse(queryRawContactIsStarred(r5)); 5735 assertTrue(queryRawContactIsStarred(r6)); 5736 assertFalse(queryRawContactIsStarred(r7)); 5737 5738 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5739 Cursor c = queryGroupMemberships(mAccount); 5740 try { 5741 assertTrue(c.moveToNext()); 5742 assertEquals(g1, c.getLong(0)); 5743 assertEquals(r1, c.getLong(1)); 5744 assertTrue(c.moveToNext()); 5745 assertEquals(g1, c.getLong(0)); 5746 assertEquals(r3, c.getLong(1)); 5747 assertFalse(c.moveToNext()); 5748 } finally { 5749 c.close(); 5750 } 5751 5752 updateItem(RawContacts.CONTENT_URI, r6, 5753 RawContacts.ACCOUNT_NAME, mAccount.name, 5754 RawContacts.ACCOUNT_TYPE, mAccount.type); 5755 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5756 c = queryGroupMemberships(mAccount); 5757 try { 5758 assertTrue(c.moveToNext()); 5759 assertEquals(g1, c.getLong(0)); 5760 assertEquals(r1, c.getLong(1)); 5761 assertTrue(c.moveToNext()); 5762 assertEquals(g1, c.getLong(0)); 5763 assertEquals(r3, c.getLong(1)); 5764 assertTrue(c.moveToNext()); 5765 assertEquals(g1, c.getLong(0)); 5766 assertEquals(r6, c.getLong(1)); 5767 assertFalse(c.moveToNext()); 5768 } finally { 5769 c.close(); 5770 } 5771 5772 mResolver.delete(ContentUris.withAppendedId(Groups.CONTENT_URI, g1), null, null); 5773 5774 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 5775 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5776 5777 assertTrue(queryRawContactIsStarred(r1)); 5778 assertFalse(queryRawContactIsStarred(r2)); 5779 assertTrue(queryRawContactIsStarred(r3)); 5780 assertTrue(queryRawContactIsStarred(r4)); 5781 assertFalse(queryRawContactIsStarred(r5)); 5782 assertTrue(queryRawContactIsStarred(r6)); 5783 assertFalse(queryRawContactIsStarred(r7)); 5784 } 5785 5786 public void testFavoritesGroupMembershipChangeAfterStarChange() { 5787 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 5788 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false/* favorite */); 5789 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, true /* favorite */); 5790 long g5 = createGroup(mAccountTwo, "g5", "t5", 0, false /* autoAdd */, false/* favorite */); 5791 long r1 = createRawContact(mAccount, RawContacts.STARRED, "1"); 5792 long r2 = createRawContact(mAccount); 5793 long r3 = createRawContact(mAccountTwo); 5794 5795 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5796 Cursor c = queryGroupMemberships(mAccount); 5797 try { 5798 assertTrue(c.moveToNext()); 5799 assertEquals(g1, c.getLong(0)); 5800 assertEquals(r1, c.getLong(1)); 5801 assertFalse(c.moveToNext()); 5802 } finally { 5803 c.close(); 5804 } 5805 5806 // remove the star from r1 5807 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "0")); 5808 5809 // Since no raw contacts are starred, there should be no group memberships. 5810 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 5811 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5812 5813 // mark r1 as starred 5814 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "1")); 5815 // Now that r1 is starred it should have a membership in the one groups from mAccount 5816 // that is marked as a favorite. 5817 // There should be no memberships in mAccountTwo since it has no starred raw contacts. 5818 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5819 c = queryGroupMemberships(mAccount); 5820 try { 5821 assertTrue(c.moveToNext()); 5822 assertEquals(g1, c.getLong(0)); 5823 assertEquals(r1, c.getLong(1)); 5824 assertFalse(c.moveToNext()); 5825 } finally { 5826 c.close(); 5827 } 5828 5829 // remove the star from r1 5830 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "0")); 5831 // Since no raw contacts are starred, there should be no group memberships. 5832 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 5833 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5834 5835 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(r1)); 5836 assertNotNull(contactUri); 5837 5838 // mark r1 as starred via its contact lookup uri 5839 assertEquals(1, updateItem(contactUri, Contacts.STARRED, "1")); 5840 // Now that r1 is starred it should have a membership in the one groups from mAccount 5841 // that is marked as a favorite. 5842 // There should be no memberships in mAccountTwo since it has no starred raw contacts. 5843 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5844 c = queryGroupMemberships(mAccount); 5845 try { 5846 assertTrue(c.moveToNext()); 5847 assertEquals(g1, c.getLong(0)); 5848 assertEquals(r1, c.getLong(1)); 5849 assertFalse(c.moveToNext()); 5850 } finally { 5851 c.close(); 5852 } 5853 5854 // remove the star from r1 5855 updateItem(contactUri, Contacts.STARRED, "0"); 5856 // Since no raw contacts are starred, there should be no group memberships. 5857 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 5858 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5859 } 5860 5861 public void testStarChangedAfterGroupMembershipChange() { 5862 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 5863 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false/* favorite */); 5864 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, true /* favorite */); 5865 long g5 = createGroup(mAccountTwo, "g5", "t5", 0, false /* autoAdd */, false/* favorite */); 5866 long r1 = createRawContact(mAccount); 5867 long r2 = createRawContact(mAccount); 5868 long r3 = createRawContact(mAccountTwo); 5869 5870 assertFalse(queryRawContactIsStarred(r1)); 5871 assertFalse(queryRawContactIsStarred(r2)); 5872 assertFalse(queryRawContactIsStarred(r3)); 5873 5874 Cursor c; 5875 5876 // add r1 to one favorites group 5877 // r1's star should automatically be set 5878 // r1 should automatically be added to the other favorites group 5879 Uri urir1g1 = insertGroupMembership(r1, g1); 5880 assertTrue(queryRawContactIsStarred(r1)); 5881 assertFalse(queryRawContactIsStarred(r2)); 5882 assertFalse(queryRawContactIsStarred(r3)); 5883 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5884 c = queryGroupMemberships(mAccount); 5885 try { 5886 assertTrue(c.moveToNext()); 5887 assertEquals(g1, c.getLong(0)); 5888 assertEquals(r1, c.getLong(1)); 5889 assertFalse(c.moveToNext()); 5890 } finally { 5891 c.close(); 5892 } 5893 5894 // remove r1 from one favorites group 5895 mResolver.delete(urir1g1, null, null); 5896 // r1's star should no longer be set 5897 assertFalse(queryRawContactIsStarred(r1)); 5898 assertFalse(queryRawContactIsStarred(r2)); 5899 assertFalse(queryRawContactIsStarred(r3)); 5900 // there should be no membership rows 5901 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 5902 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5903 5904 // add r3 to the one favorites group for that account 5905 // r3's star should automatically be set 5906 Uri urir3g4 = insertGroupMembership(r3, g4); 5907 assertFalse(queryRawContactIsStarred(r1)); 5908 assertFalse(queryRawContactIsStarred(r2)); 5909 assertTrue(queryRawContactIsStarred(r3)); 5910 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 5911 c = queryGroupMemberships(mAccountTwo); 5912 try { 5913 assertTrue(c.moveToNext()); 5914 assertEquals(g4, c.getLong(0)); 5915 assertEquals(r3, c.getLong(1)); 5916 assertFalse(c.moveToNext()); 5917 } finally { 5918 c.close(); 5919 } 5920 5921 // remove r3 from the favorites group 5922 mResolver.delete(urir3g4, null, null); 5923 // r3's star should automatically be cleared 5924 assertFalse(queryRawContactIsStarred(r1)); 5925 assertFalse(queryRawContactIsStarred(r2)); 5926 assertFalse(queryRawContactIsStarred(r3)); 5927 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 5928 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 5929 } 5930 5931 public void testReadOnlyRawContact() { 5932 long rawContactId = createRawContact(); 5933 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 5934 storeValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "first"); 5935 storeValue(rawContactUri, RawContacts.RAW_CONTACT_IS_READ_ONLY, 1); 5936 5937 storeValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "second"); 5938 assertStoredValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "first"); 5939 5940 Uri syncAdapterUri = rawContactUri.buildUpon() 5941 .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "1") 5942 .build(); 5943 storeValue(syncAdapterUri, RawContacts.CUSTOM_RINGTONE, "third"); 5944 assertStoredValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "third"); 5945 } 5946 5947 public void testReadOnlyDataRow() { 5948 long rawContactId = createRawContact(); 5949 Uri emailUri = insertEmail(rawContactId, "email"); 5950 Uri phoneUri = insertPhoneNumber(rawContactId, "555-1111"); 5951 5952 storeValue(emailUri, Data.IS_READ_ONLY, "1"); 5953 storeValue(emailUri, Email.ADDRESS, "changed"); 5954 storeValue(phoneUri, Phone.NUMBER, "555-2222"); 5955 assertStoredValue(emailUri, Email.ADDRESS, "email"); 5956 assertStoredValue(phoneUri, Phone.NUMBER, "555-2222"); 5957 5958 Uri syncAdapterUri = emailUri.buildUpon() 5959 .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "1") 5960 .build(); 5961 storeValue(syncAdapterUri, Email.ADDRESS, "changed"); 5962 assertStoredValue(emailUri, Email.ADDRESS, "changed"); 5963 } 5964 5965 public void testContactWithReadOnlyRawContact() { 5966 long rawContactId1 = createRawContact(); 5967 Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 5968 storeValue(rawContactUri1, RawContacts.CUSTOM_RINGTONE, "first"); 5969 5970 long rawContactId2 = createRawContact(); 5971 Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2); 5972 storeValue(rawContactUri2, RawContacts.CUSTOM_RINGTONE, "second"); 5973 storeValue(rawContactUri2, RawContacts.RAW_CONTACT_IS_READ_ONLY, 1); 5974 5975 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 5976 rawContactId1, rawContactId2); 5977 5978 long contactId = queryContactId(rawContactId1); 5979 5980 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 5981 storeValue(contactUri, Contacts.CUSTOM_RINGTONE, "rt"); 5982 assertStoredValue(contactUri, Contacts.CUSTOM_RINGTONE, "rt"); 5983 assertStoredValue(rawContactUri1, RawContacts.CUSTOM_RINGTONE, "rt"); 5984 assertStoredValue(rawContactUri2, RawContacts.CUSTOM_RINGTONE, "second"); 5985 } 5986 5987 public void testNameParsingQuery() { 5988 Uri uri = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name") 5989 .appendQueryParameter(StructuredName.DISPLAY_NAME, "Mr. John Q. Doe Jr.").build(); 5990 Cursor cursor = mResolver.query(uri, null, null, null, null); 5991 ContentValues values = new ContentValues(); 5992 values.put(StructuredName.DISPLAY_NAME, "Mr. John Q. Doe Jr."); 5993 values.put(StructuredName.PREFIX, "Mr."); 5994 values.put(StructuredName.GIVEN_NAME, "John"); 5995 values.put(StructuredName.MIDDLE_NAME, "Q."); 5996 values.put(StructuredName.FAMILY_NAME, "Doe"); 5997 values.put(StructuredName.SUFFIX, "Jr."); 5998 values.put(StructuredName.FULL_NAME_STYLE, FullNameStyle.WESTERN); 5999 assertTrue(cursor.moveToFirst()); 6000 assertCursorValues(cursor, values); 6001 cursor.close(); 6002 } 6003 6004 public void testNameConcatenationQuery() { 6005 Uri uri = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name") 6006 .appendQueryParameter(StructuredName.PREFIX, "Mr") 6007 .appendQueryParameter(StructuredName.GIVEN_NAME, "John") 6008 .appendQueryParameter(StructuredName.MIDDLE_NAME, "Q.") 6009 .appendQueryParameter(StructuredName.FAMILY_NAME, "Doe") 6010 .appendQueryParameter(StructuredName.SUFFIX, "Jr.") 6011 .build(); 6012 Cursor cursor = mResolver.query(uri, null, null, null, null); 6013 ContentValues values = new ContentValues(); 6014 values.put(StructuredName.DISPLAY_NAME, "Mr John Q. Doe, Jr."); 6015 values.put(StructuredName.PREFIX, "Mr"); 6016 values.put(StructuredName.GIVEN_NAME, "John"); 6017 values.put(StructuredName.MIDDLE_NAME, "Q."); 6018 values.put(StructuredName.FAMILY_NAME, "Doe"); 6019 values.put(StructuredName.SUFFIX, "Jr."); 6020 values.put(StructuredName.FULL_NAME_STYLE, FullNameStyle.WESTERN); 6021 assertTrue(cursor.moveToFirst()); 6022 assertCursorValues(cursor, values); 6023 cursor.close(); 6024 } 6025 6026 private Cursor queryGroupMemberships(Account account) { 6027 Cursor c = mResolver.query(maybeAddAccountQueryParameters(Data.CONTENT_URI, account), 6028 new String[]{GroupMembership.GROUP_ROW_ID, GroupMembership.RAW_CONTACT_ID}, 6029 Data.MIMETYPE + "=?", new String[]{GroupMembership.CONTENT_ITEM_TYPE}, 6030 GroupMembership.GROUP_SOURCE_ID); 6031 return c; 6032 } 6033 6034 private String readToEnd(FileInputStream inputStream) { 6035 try { 6036 System.out.println("DECLARED INPUT STREAM LENGTH: " + inputStream.available()); 6037 int ch; 6038 StringBuilder stringBuilder = new StringBuilder(); 6039 int index = 0; 6040 while (true) { 6041 ch = inputStream.read(); 6042 System.out.println("READ CHARACTER: " + index + " " + ch); 6043 if (ch == -1) { 6044 break; 6045 } 6046 stringBuilder.append((char)ch); 6047 index++; 6048 } 6049 return stringBuilder.toString(); 6050 } catch (IOException e) { 6051 return null; 6052 } 6053 } 6054 6055 private void assertQueryParameter(String uriString, String parameter, String expectedValue) { 6056 assertEquals(expectedValue, ContactsProvider2.getQueryParameter( 6057 Uri.parse(uriString), parameter)); 6058 } 6059 6060 private long createContact(ContentValues values, String firstName, String givenName, 6061 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 6062 long groupId, int chatMode) { 6063 return createContact(values, firstName, givenName, phoneNumber, email, presenceStatus, 6064 timesContacted, starred, groupId, chatMode, false); 6065 } 6066 6067 private long createContact(ContentValues values, String firstName, String givenName, 6068 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 6069 long groupId, int chatMode, boolean isUserProfile) { 6070 return queryContactId(createRawContact(values, firstName, givenName, phoneNumber, email, 6071 presenceStatus, timesContacted, starred, groupId, chatMode, isUserProfile)); 6072 } 6073 6074 private long createRawContact(ContentValues values, String firstName, String givenName, 6075 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 6076 long groupId, int chatMode) { 6077 long rawContactId = createRawContact(values, phoneNumber, email, presenceStatus, 6078 timesContacted, starred, groupId, chatMode); 6079 insertStructuredName(rawContactId, firstName, givenName); 6080 return rawContactId; 6081 } 6082 6083 private long createRawContact(ContentValues values, String firstName, String givenName, 6084 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 6085 long groupId, int chatMode, boolean isUserProfile) { 6086 long rawContactId = createRawContact(values, phoneNumber, email, presenceStatus, 6087 timesContacted, starred, groupId, chatMode, isUserProfile); 6088 insertStructuredName(rawContactId, firstName, givenName); 6089 return rawContactId; 6090 } 6091 6092 private long createRawContact(ContentValues values, String phoneNumber, String email, 6093 int presenceStatus, int timesContacted, int starred, long groupId, int chatMode) { 6094 return createRawContact(values, phoneNumber, email, presenceStatus, timesContacted, starred, 6095 groupId, chatMode, false); 6096 } 6097 6098 private long createRawContact(ContentValues values, String phoneNumber, String email, 6099 int presenceStatus, int timesContacted, int starred, long groupId, int chatMode, 6100 boolean isUserProfile) { 6101 values.put(RawContacts.STARRED, starred); 6102 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 6103 values.put(RawContacts.CUSTOM_RINGTONE, "beethoven5"); 6104 values.put(RawContacts.TIMES_CONTACTED, timesContacted); 6105 6106 Uri insertionUri = isUserProfile 6107 ? Profile.CONTENT_RAW_CONTACTS_URI 6108 : RawContacts.CONTENT_URI; 6109 Uri rawContactUri = mResolver.insert(insertionUri, values); 6110 long rawContactId = ContentUris.parseId(rawContactUri); 6111 Uri photoUri = insertPhoto(rawContactId); 6112 long photoId = ContentUris.parseId(photoUri); 6113 values.put(Contacts.PHOTO_ID, photoId); 6114 if (!TextUtils.isEmpty(phoneNumber)) { 6115 insertPhoneNumber(rawContactId, phoneNumber); 6116 } 6117 if (!TextUtils.isEmpty(email)) { 6118 insertEmail(rawContactId, email); 6119 } 6120 6121 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, email, presenceStatus, "hacking", 6122 chatMode, isUserProfile); 6123 6124 if (groupId != 0) { 6125 insertGroupMembership(rawContactId, groupId); 6126 } 6127 6128 return rawContactId; 6129 } 6130 6131 /** 6132 * Creates a raw contact with pre-set values under the user's profile. 6133 * @param profileValues Values to be used to create the entry (common values will be 6134 * automatically populated in createRawContact()). 6135 * @return the raw contact ID that was created. 6136 */ 6137 private long createBasicProfileContact(ContentValues profileValues) { 6138 long profileRawContactId = createRawContact(profileValues, "Mia", "Prophyl", 6139 "18005554411", "mia.prophyl@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 6140 StatusUpdates.CAPABILITY_HAS_CAMERA, true); 6141 profileValues.put(Contacts.DISPLAY_NAME, "Mia Prophyl"); 6142 return profileRawContactId; 6143 } 6144 6145 /** 6146 * Creates a raw contact with pre-set values that is not under the user's profile. 6147 * @param nonProfileValues Values to be used to create the entry (common values will be 6148 * automatically populated in createRawContact()). 6149 * @return the raw contact ID that was created. 6150 */ 6151 private long createBasicNonProfileContact(ContentValues nonProfileValues) { 6152 long nonProfileRawContactId = createRawContact(nonProfileValues, "John", "Doe", 6153 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 6154 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 6155 nonProfileValues.put(Contacts.DISPLAY_NAME, "John Doe"); 6156 return nonProfileRawContactId; 6157 } 6158 6159 private void putDataValues(ContentValues values, long rawContactId) { 6160 values.put(Data.RAW_CONTACT_ID, rawContactId); 6161 values.put(Data.MIMETYPE, "testmimetype"); 6162 values.put(Data.RES_PACKAGE, "oldpackage"); 6163 values.put(Data.IS_PRIMARY, 1); 6164 values.put(Data.IS_SUPER_PRIMARY, 1); 6165 values.put(Data.DATA1, "one"); 6166 values.put(Data.DATA2, "two"); 6167 values.put(Data.DATA3, "three"); 6168 values.put(Data.DATA4, "four"); 6169 values.put(Data.DATA5, "five"); 6170 values.put(Data.DATA6, "six"); 6171 values.put(Data.DATA7, "seven"); 6172 values.put(Data.DATA8, "eight"); 6173 values.put(Data.DATA9, "nine"); 6174 values.put(Data.DATA10, "ten"); 6175 values.put(Data.DATA11, "eleven"); 6176 values.put(Data.DATA12, "twelve"); 6177 values.put(Data.DATA13, "thirteen"); 6178 values.put(Data.DATA14, "fourteen"); 6179 values.put(Data.DATA15, "fifteen"); 6180 values.put(Data.SYNC1, "sync1"); 6181 values.put(Data.SYNC2, "sync2"); 6182 values.put(Data.SYNC3, "sync3"); 6183 values.put(Data.SYNC4, "sync4"); 6184 } 6185 6186 /** 6187 * @param data1 email address or phone number 6188 * @param usageType One of {@link DataUsageFeedback#USAGE_TYPE} 6189 * @param values ContentValues for this feedback. Useful for incrementing 6190 * {Contacts#TIMES_CONTACTED} in the ContentValue. Can be null. 6191 */ 6192 private void sendFeedback(String data1, String usageType, ContentValues values) { 6193 final long dataId = getStoredLongValue(Data.CONTENT_URI, 6194 Data.DATA1 + "=?", new String[] { data1 }, Data._ID); 6195 final Uri feedbackUri = DataUsageFeedback.FEEDBACK_URI.buildUpon() 6196 .appendPath(String.valueOf(dataId)) 6197 .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, usageType) 6198 .build(); 6199 assertNotSame(0, mResolver.update(feedbackUri, new ContentValues(), null, null)); 6200 if (values != null && values.containsKey(Contacts.TIMES_CONTACTED)) { 6201 values.put(Contacts.TIMES_CONTACTED, values.getAsInteger(Contacts.TIMES_CONTACTED) + 1); 6202 } 6203 } 6204} 6205