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