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