LegacyContactsProviderTest.java revision 71e051c79a57af70ec7b095074c3e7faf9507b52
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 android.app.SearchManager; 20import android.content.ContentProvider; 21import android.content.ContentUris; 22import android.content.ContentValues; 23import android.database.Cursor; 24import android.net.Uri; 25import android.provider.Contacts; 26import android.provider.Contacts.ContactMethods; 27import android.provider.Contacts.Extensions; 28import android.provider.Contacts.GroupMembership; 29import android.provider.Contacts.Groups; 30import android.provider.Contacts.Intents; 31import android.provider.Contacts.Organizations; 32import android.provider.Contacts.People; 33import android.provider.Contacts.Phones; 34import android.provider.Contacts.Photos; 35import android.provider.Contacts.Presence; 36import android.test.suitebuilder.annotation.LargeTest; 37 38import java.io.IOException; 39 40/** 41 * Tests for legacy contacts APIs. 42 */ 43@LargeTest 44public class LegacyContactsProviderTest extends BaseContactsProvider2Test { 45 46 private static final boolean USE_LEGACY_PROVIDER = false; 47 48 @Override 49 protected Class<? extends ContentProvider> getProviderClass() { 50 return USE_LEGACY_PROVIDER ? ContactsProvider.class : SynchronousContactsProvider2.class; 51 } 52 53 @Override 54 protected String getAuthority() { 55 return Contacts.AUTHORITY; 56 } 57 58 public void testPeopleInsert() { 59 ContentValues values = new ContentValues(); 60 putContactValues(values); 61 62 Uri uri = mResolver.insert(People.CONTENT_URI, values); 63 assertStoredValues(uri, values); 64 assertSelection(People.CONTENT_URI, values, "people", People._ID, ContentUris.parseId(uri)); 65 } 66 67 public void testPeopleUpdate() { 68 ContentValues values = new ContentValues(); 69 putContactValues(values); 70 71 Uri uri = mResolver.insert(People.CONTENT_URI, values); 72 long personId = ContentUris.parseId(uri); 73 assertStoredValues(uri, values); 74 assertSelection(People.CONTENT_URI, values, "people", People._ID, personId); 75 76 values.clear(); 77 putContactValues2(values); 78 mResolver.update(uri, values, null, null); 79 assertStoredValues(uri, values); 80 81 values.clear(); 82 putContactValues(values); 83 mResolver.update(People.CONTENT_URI, values, People._ID + "=" + personId, null); 84 assertStoredValues(uri, values); 85 } 86 87 public void testPeopleDelete() { 88 ContentValues values = new ContentValues(); 89 values.put(People.NAME, "John Doe"); 90 Uri personId = mResolver.insert(People.CONTENT_URI, values); 91 mResolver.delete(personId, null, null); 92 93 Cursor c = mResolver.query(personId, null, People.NAME + "='John Doe'" , null, null); 94 assertEquals("Record count after deletion", 0, c.getCount()); 95 c.close(); 96 97 try { 98 mResolver.query(People.DELETED_CONTENT_URI, null, null, null, null); 99 } catch (UnsupportedOperationException e) { 100 // Expected exception 101 } 102 } 103 104 public void testPeopleFilter() { 105 ContentValues values = new ContentValues(); 106 values.put(People.NAME, "Deer Doe"); 107 mResolver.insert(People.CONTENT_URI, values); 108 109 values.clear(); 110 values.put(People.NAME, "Dear Dough"); 111 mResolver.insert(People.CONTENT_URI, values); 112 113 values.clear(); 114 values.put(People.NAME, "D.R. Dauwe"); 115 mResolver.insert(People.CONTENT_URI, values); 116 117 assertFilteredContacts("d", "Deer Doe", "Dear Dough", "D.R. Dauwe"); 118 assertFilteredContacts("de", "Deer Doe", "Dear Dough"); 119 assertFilteredContacts("dee", "Deer Doe"); 120 assertFilteredContacts("der"); 121 } 122 123 public void testDefaultDisplayName() { 124 ContentValues values = new ContentValues(); 125 values.put(People.NAME, "John Doe"); 126 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 127 assertStoredValue(personUri, People.DISPLAY_NAME, "John Doe"); 128 } 129 130 public void testPrimaryOrganization() { 131 ContentValues values = new ContentValues(); 132 final Uri personUri = mResolver.insert(People.CONTENT_URI, values); 133 long personId = ContentUris.parseId(personUri); 134 135 // Primary 136 values.clear(); 137 values.put(Organizations.ISPRIMARY, 1); 138 values.put(Organizations.COMPANY, "Google"); 139 values.put(Organizations.TYPE, Organizations.TYPE_WORK); 140 values.put(Organizations.PERSON_ID, personId); 141 Uri orgUri1 = mResolver.insert(Organizations.CONTENT_URI, values); 142 143 // Non-primary 144 values.clear(); 145 values.put(Organizations.COMPANY, "Acme"); 146 values.put(Organizations.TYPE, Organizations.TYPE_WORK); 147 values.put(Organizations.PERSON_ID, personId); 148 Uri orgUri2 = mResolver.insert(Organizations.CONTENT_URI, values); 149 150 values.clear(); 151 values.put(People.PRIMARY_ORGANIZATION_ID, ContentUris.parseId(orgUri1)); 152 values.put(People.DISPLAY_NAME, "Google"); 153 assertStoredValues(personUri, values); 154 155 // Remove the original primary organization 156 mResolver.delete(orgUri1, null, null); 157 158 values.clear(); 159 values.put(People.PRIMARY_ORGANIZATION_ID, ContentUris.parseId(orgUri2)); 160 values.put(People.DISPLAY_NAME, "Acme"); 161 assertStoredValues(personUri, values); 162 163 // Remove the remaining organization 164 mResolver.delete(orgUri2, null, null); 165 166 values.clear(); 167 values.putNull(People.PRIMARY_ORGANIZATION_ID); 168 values.putNull(People.DISPLAY_NAME); 169 assertStoredValues(personUri, values); 170 } 171 172 public void testPrimaryPhone() { 173 ContentValues values = new ContentValues(); 174 putContactValuesExceptName(values); 175 176 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 177 long personId = ContentUris.parseId(personUri); 178 179 // Primary 180 values.clear(); 181 values.put(Phones.ISPRIMARY, 1); 182 values.put(Phones.TYPE, Phones.TYPE_WORK); 183 values.put(Phones.PERSON_ID, personId); 184 values.put(Phones.NUMBER, "12345"); 185 Uri phoneUri1 = mResolver.insert(Phones.CONTENT_URI, values); 186 187 // Non-primary 188 values.clear(); 189 values.put(Phones.TYPE, Phones.TYPE_WORK); 190 values.put(Phones.PERSON_ID, personId); 191 values.put(Phones.NUMBER, "67890"); 192 Uri phoneUri2 = mResolver.insert(Phones.CONTENT_URI, values); 193 194 values.clear(); 195 values.put(People.PRIMARY_PHONE_ID, ContentUris.parseId(phoneUri1)); 196 values.put(People.DISPLAY_NAME, "12345"); 197 assertStoredValues(personUri, values); 198 199 values.clear(); 200 putContactValuesExceptName(values); 201 values.put(People.PRIMARY_PHONE_ID, ContentUris.parseId(phoneUri1)); 202 assertStoredValues(phoneUri2, values); 203 204 // Remove the primary phone number 205 mResolver.delete(phoneUri1, null, null); 206 207 values.clear(); 208 values.put(People.PRIMARY_PHONE_ID, ContentUris.parseId(phoneUri2)); 209 values.put(People.DISPLAY_NAME, "67890"); 210 assertStoredValues(personUri, values); 211 212 // Remove the remaining phone number 213 mResolver.delete(phoneUri2, null, null); 214 215 values.clear(); 216 values.putNull(People.PRIMARY_PHONE_ID); 217 values.putNull(People.DISPLAY_NAME); 218 assertStoredValues(personUri, values); 219 } 220 221 public void testEmailCrud() { 222 ContentValues values = new ContentValues(); 223 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 224 long personId = ContentUris.parseId(personUri); 225 226 // Primary 227 values.clear(); 228 values.put(ContactMethods.PERSON_ID, personId); 229 values.put(ContactMethods.KIND, Contacts.KIND_EMAIL); 230 values.put(ContactMethods.TYPE, ContactMethods.TYPE_HOME); 231 values.put(ContactMethods.DATA, "foo@acme.com"); 232 values.put(ContactMethods.ISPRIMARY, 1); 233 Uri emailUri1 = mResolver.insert(ContactMethods.CONTENT_URI, values); 234 235 assertEquals(ContactMethods.CONTENT_EMAIL_ITEM_TYPE, mResolver.getType(emailUri1)); 236 237 assertStoredValues(ContactMethods.CONTENT_URI, 238 ContactMethods._ID + "=" + ContentUris.parseId(emailUri1), null, values); 239 assertStoredValues(ContactMethods.CONTENT_EMAIL_URI, 240 ContactMethods._ID + "=" + ContentUris.parseId(emailUri1), null, values); 241 } 242 243 public void testPrimaryEmail() { 244 ContentValues values = new ContentValues(); 245 putContactValuesExceptName(values); 246 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 247 long personId = ContentUris.parseId(personUri); 248 249 // Primary 250 values.clear(); 251 values.put(ContactMethods.PERSON_ID, personId); 252 values.put(ContactMethods.KIND, Contacts.KIND_EMAIL); 253 values.put(ContactMethods.TYPE, ContactMethods.TYPE_HOME); 254 values.put(ContactMethods.DATA, "foo@acme.com"); 255 values.put(ContactMethods.ISPRIMARY, 1); 256 Uri emailUri1 = mResolver.insert(ContactMethods.CONTENT_URI, values); 257 258 // Non-primary 259 values.clear(); 260 values.put(ContactMethods.PERSON_ID, personId); 261 values.put(ContactMethods.KIND, Contacts.KIND_EMAIL); 262 values.put(ContactMethods.TYPE, ContactMethods.TYPE_WORK); 263 values.put(ContactMethods.DATA, "bar@acme.com"); 264 Uri emailUri2 = mResolver.insert(ContactMethods.CONTENT_URI, values); 265 266 values.clear(); 267 values.put(People.PRIMARY_EMAIL_ID, ContentUris.parseId(emailUri1)); 268 values.put(People.DISPLAY_NAME, "foo@acme.com"); 269 assertStoredValues(personUri, values); 270 271 values.clear(); 272 putContactValuesExceptName(values); 273 values.put(People.PRIMARY_EMAIL_ID, ContentUris.parseId(emailUri1)); 274 assertStoredValues(emailUri2, values); 275 276 // Remove the primary email 277 mResolver.delete(emailUri1, null, null); 278 279 values.clear(); 280 values.put(People.PRIMARY_EMAIL_ID, ContentUris.parseId(emailUri2)); 281 values.put(People.DISPLAY_NAME, "bar@acme.com"); 282 assertStoredValues(personUri, values); 283 284 // Remove the remaining email 285 mResolver.delete(emailUri2, null, null); 286 287 values.clear(); 288 values.putNull(People.PRIMARY_EMAIL_ID); 289 values.putNull(People.DISPLAY_NAME); 290 assertStoredValues(personUri, values); 291 } 292 293 public void testMarkAsContacted() { 294 ContentValues values = new ContentValues(); 295 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 296 long personId = ContentUris.parseId(personUri); 297 298 int timesContactedBefore = 299 Integer.parseInt(getStoredValue(personUri, People.TIMES_CONTACTED)); 300 long timeBefore = System.currentTimeMillis(); 301 People.markAsContacted(mResolver, personId); 302 long timeAfter = System.currentTimeMillis(); 303 304 long lastContacted = Long.parseLong(getStoredValue(personUri, People.LAST_TIME_CONTACTED)); 305 int timesContactedAfter = 306 Integer.parseInt(getStoredValue(personUri, People.TIMES_CONTACTED)); 307 308 assertTrue(lastContacted >= timeBefore); 309 assertTrue(lastContacted <= timeAfter); 310 assertEquals(timesContactedAfter, timesContactedBefore + 1); 311 } 312 313 public void testOrganizationsInsert() { 314 ContentValues values = new ContentValues(); 315 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 316 long personId = ContentUris.parseId(personUri); 317 318 values.clear(); 319 values.put(Organizations.COMPANY, "Sierra"); 320 values.put(Organizations.PERSON_ID, personId); 321 values.put(Organizations.TYPE, Organizations.TYPE_CUSTOM); 322 values.put(Organizations.LABEL, "Club"); 323 values.put(Organizations.TITLE, "Member"); 324 values.put(Organizations.ISPRIMARY, 1); 325 326 Uri uri = mResolver.insert(Organizations.CONTENT_URI, values); 327 assertStoredValues(uri, values); 328 assertSelection(Organizations.CONTENT_URI, values, 329 "organizations", Organizations._ID, ContentUris.parseId(uri)); 330 331 assertPersonIdConstraint(Organizations.CONTENT_URI, Organizations.TYPE, 332 Organizations.TYPE_WORK); 333 334 assertTypeAndLabelConstraints(Organizations.CONTENT_URI, Organizations.PERSON_ID, personId, 335 Organizations.TYPE, Organizations.TYPE_CUSTOM, Organizations.TYPE_OTHER, 336 Organizations.LABEL); 337 } 338 339 public void testOrganizationsUpdate() { 340 ContentValues values = new ContentValues(); 341 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 342 long personId = ContentUris.parseId(personUri); 343 344 values.clear(); 345 values.put(Organizations.COMPANY, "Sierra"); 346 values.put(Organizations.PERSON_ID, personId); 347 values.put(Organizations.TYPE, Organizations.TYPE_CUSTOM); 348 values.put(Organizations.LABEL, "Club"); 349 values.put(Organizations.TITLE, "Member"); 350 values.put(Organizations.ISPRIMARY, 0); 351 352 Uri uri = mResolver.insert(Organizations.CONTENT_URI, values); 353 354 values.clear(); 355 values.put(Organizations.COMPANY, "Planetary"); 356 values.put(Organizations.PERSON_ID, personId); 357 values.put(Organizations.TYPE, Organizations.TYPE_CUSTOM); 358 values.put(Organizations.LABEL, "Society"); 359 values.put(Organizations.TITLE, "Chair"); 360 values.put(Organizations.ISPRIMARY, 1); 361 362 mResolver.update(uri, values, null, null); 363 364 assertStoredValues(uri, values); 365 } 366 367 public void testPhonesInsert() { 368 ContentValues values = new ContentValues(); 369 putContactValues(values); 370 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 371 long personId = ContentUris.parseId(personUri); 372 373 values.clear(); 374 values.put(Phones.PERSON_ID, personId); 375 values.put(Phones.TYPE, Phones.TYPE_CUSTOM); 376 values.put(Phones.LABEL, "Directory"); 377 values.put(Phones.NUMBER, "1-800-4664-411"); 378 values.put(Phones.ISPRIMARY, 1); 379 380 Uri uri = mResolver.insert(Phones.CONTENT_URI, values); 381 382 // Adding another value to assert 383 values.put(Phones.NUMBER_KEY, "11446640081"); 384 385 // The result is joined with People 386 putContactValues(values); 387 assertStoredValues(uri, values); 388 assertSelection(Phones.CONTENT_URI, values, "phones", 389 Phones._ID, ContentUris.parseId(uri)); 390 391 // Access the phone through People 392 Uri twigUri = Uri.withAppendedPath(personUri, People.Phones.CONTENT_DIRECTORY); 393 assertStoredValues(twigUri, values); 394 395 // Now the person should be joined with Phone 396 values.clear(); 397 putContactValues(values); 398 values.put(People.TYPE, Phones.TYPE_CUSTOM); 399 values.put(People.LABEL, "Directory"); 400 values.put(People.NUMBER, "1-800-4664-411"); 401 assertStoredValues(personUri, values); 402 403 assertPersonIdConstraint(Phones.CONTENT_URI, Phones.TYPE, Phones.TYPE_WORK); 404 405 assertTypeAndLabelConstraints(Phones.CONTENT_URI, Phones.PERSON_ID, personId, Phones.TYPE, 406 Phones.TYPE_CUSTOM, Phones.TYPE_OTHER, Phones.LABEL); 407 } 408 409 public void testPhonesUpdate() { 410 ContentValues values = new ContentValues(); 411 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 412 long personId = ContentUris.parseId(personUri); 413 414 values.clear(); 415 values.put(Phones.PERSON_ID, personId); 416 values.put(Phones.TYPE, Phones.TYPE_CUSTOM); 417 values.put(Phones.LABEL, "Directory"); 418 values.put(Phones.NUMBER, "1-800-4664-411"); 419 values.put(Phones.ISPRIMARY, 0); 420 421 Uri uri = mResolver.insert(Phones.CONTENT_URI, values); 422 423 values.clear(); 424 values.put(Phones.PERSON_ID, personId); 425 values.put(Phones.TYPE, Phones.TYPE_FAX_HOME); 426 values.putNull(Phones.LABEL); 427 values.put(Phones.NUMBER, "1-800-555-4663"); 428 values.put(Phones.ISPRIMARY, 1); 429 430 mResolver.update(uri, values, null, null); 431 432 assertStoredValues(uri, values); 433 } 434 435 public void testPhonesFilterQuery() { 436 ContentValues values = new ContentValues(); 437 putContactValues(values); 438 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 439 long personId = ContentUris.parseId(personUri); 440 441 values.clear(); 442 values.put(Phones.PERSON_ID, personId); 443 values.put(Phones.TYPE, Phones.TYPE_CUSTOM); 444 values.put(Phones.LABEL, "Directory"); 445 values.put(Phones.NUMBER, "1-800-4664-411"); 446 values.put(Phones.ISPRIMARY, 1); 447 448 Uri uri = mResolver.insert(Phones.CONTENT_URI, values); 449 450 Uri filterUri1 = Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, "8004664411"); 451 assertStoredValues(filterUri1, values); 452 453 Uri filterUri2 = Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, "7773334444"); 454 assertEquals(0, getCount(filterUri2, null, null)); 455 } 456 457 public void testEmailInsert() { 458 assertContactMethodInsert(Contacts.KIND_EMAIL, 459 ContactMethods.TYPE_CUSTOM, "Some other way", "foo@acme.com", null, true); 460 } 461 462 public void testEmailUpdate() { 463 assertContactMethodUpdate(Contacts.KIND_EMAIL, 464 ContactMethods.TYPE_CUSTOM, "Some other way", "foo@acme.com", null, false, 465 ContactMethods.TYPE_HOME, null, "bar@acme.com", "aux", true); 466 } 467 468 public void testImInsertStandard() { 469 assertContactMethodInsert(Contacts.KIND_IM, 470 ContactMethods.TYPE_CUSTOM, "Some other way", "pre:3", "Bar", true); 471 } 472 473 public void testImUpdateStandard() { 474 assertContactMethodUpdate(Contacts.KIND_IM, 475 ContactMethods.TYPE_CUSTOM, "Some other way", "pre:3", "Bar", false, 476 ContactMethods.TYPE_WORK, null, "pre:4", "Buz", true); 477 } 478 479 public void testImInsertCustom() { 480 assertContactMethodInsert(Contacts.KIND_IM, 481 ContactMethods.TYPE_CUSTOM, "Some other way", "custom:my_proto", "Bar", true); 482 } 483 484 public void testImUpdateCustom() { 485 assertContactMethodUpdate(Contacts.KIND_IM, 486 ContactMethods.TYPE_CUSTOM, "Some other way", "custom:my_proto", "Bar", false, 487 ContactMethods.TYPE_HOME, null, "custom:my_other_proto", "Buz", true); 488 } 489 490 public void testPostalInsert() { 491 assertContactMethodInsert(Contacts.KIND_POSTAL, 492 ContactMethods.TYPE_CUSTOM, "Some other way", "Foo", "Bar", true); 493 } 494 495 public void testPostalUpdate() { 496 assertContactMethodUpdate(Contacts.KIND_POSTAL, 497 ContactMethods.TYPE_CUSTOM, "Some other way", "Foo", "Bar", false, 498 ContactMethods.TYPE_WORK, null, "Biz", "Baz", true); 499 } 500 501 private void assertContactMethodInsert(int kind, int type, String label, String data, 502 String auxData, boolean primary) { 503 ContentValues values = new ContentValues(); 504 putContactValues(values); 505 final Uri personUri = mResolver.insert(People.CONTENT_URI, values); 506 long personId = ContentUris.parseId(personUri); 507 508 values.clear(); 509 values.put(ContactMethods.PERSON_ID, personId); 510 values.put(ContactMethods.KIND, kind); 511 values.put(ContactMethods.TYPE, type); 512 values.put(ContactMethods.LABEL, label); 513 values.put(ContactMethods.DATA, data); 514 values.put(ContactMethods.AUX_DATA, auxData); 515 values.put(ContactMethods.ISPRIMARY, primary ? 1 : 0); 516 517 Uri uri = mResolver.insert(ContactMethods.CONTENT_URI, values); 518 519 // The result is joined with People 520 putContactValues(values); 521 assertStoredValues(uri, values); 522 assertSelection(ContactMethods.CONTENT_URI, values, "contact_methods", 523 ContactMethods._ID, ContentUris.parseId(uri)); 524 525 // Access the contact method through People 526 Uri twigUri = Uri.withAppendedPath(personUri, People.ContactMethods.CONTENT_DIRECTORY); 527 assertStoredValues(twigUri, values); 528 529 assertPersonIdConstraint(ContactMethods.CONTENT_URI, ContactMethods.TYPE, 530 ContactMethods.TYPE_WORK); 531 532 assertTypeAndLabelConstraints(ContactMethods.CONTENT_URI, ContactMethods.PERSON_ID, 533 personId, ContactMethods.TYPE, ContactMethods.TYPE_CUSTOM, 534 ContactMethods.TYPE_OTHER, ContactMethods.LABEL); 535 } 536 537 private void assertContactMethodUpdate(int kind, 538 int type1, String label1, String data1, String auxData1, boolean primary1, 539 int type2, String label2, String data2, String auxData2, boolean primary2) { 540 ContentValues values = new ContentValues(); 541 putContactValues(values); 542 final Uri personUri = mResolver.insert(People.CONTENT_URI, values); 543 long personId = ContentUris.parseId(personUri); 544 545 values.clear(); 546 values.put(ContactMethods.PERSON_ID, personId); 547 values.put(ContactMethods.KIND, kind); 548 values.put(ContactMethods.TYPE, type1); 549 values.put(ContactMethods.LABEL, label1); 550 values.put(ContactMethods.DATA, data1); 551 values.put(ContactMethods.AUX_DATA, auxData1); 552 values.put(ContactMethods.ISPRIMARY, primary1 ? 1 : 0); 553 554 Uri uri = mResolver.insert(ContactMethods.CONTENT_URI, values); 555 556 values.clear(); 557 values.put(ContactMethods.TYPE, type2); 558 values.put(ContactMethods.LABEL, label2); 559 values.put(ContactMethods.DATA, data2); 560 values.put(ContactMethods.AUX_DATA, auxData2); 561 values.put(ContactMethods.ISPRIMARY, primary2 ? 1 : 0); 562 mResolver.update(uri, values, null, null); 563 564 assertStoredValues(uri, values); 565 } 566 567 public void testExtensionsInsert() { 568 ContentValues values = new ContentValues(); 569 final Uri personUri = mResolver.insert(People.CONTENT_URI, values); 570 long personId = ContentUris.parseId(personUri); 571 572 values.clear(); 573 values.put(Extensions.PERSON_ID, personId); 574 values.put(Extensions.NAME, "Foo"); 575 values.put(Extensions.VALUE, "Bar"); 576 577 Uri uri = mResolver.insert(Extensions.CONTENT_URI, values); 578 assertStoredValues(uri, values); 579 assertSelection(Extensions.CONTENT_URI, values, "extensions", 580 Extensions._ID, ContentUris.parseId(uri)); 581 582 // Access the extensions through People 583 Uri twigUri = Uri.withAppendedPath(personUri, People.Extensions.CONTENT_DIRECTORY); 584 assertStoredValues(twigUri, values); 585 } 586 587 public void testExtensionsUpdate() { 588 ContentValues values = new ContentValues(); 589 final Uri personUri = mResolver.insert(People.CONTENT_URI, values); 590 long personId = ContentUris.parseId(personUri); 591 592 values.clear(); 593 values.put(Extensions.PERSON_ID, personId); 594 values.put(Extensions.NAME, "Foo"); 595 values.put(Extensions.VALUE, "Bar"); 596 597 Uri uri = mResolver.insert(Extensions.CONTENT_URI, values); 598 599 values.clear(); 600 values.put(Extensions.NAME, "Biz"); 601 values.put(Extensions.VALUE, "Baz"); 602 mResolver.update(uri, values, null, null); 603 604 assertStoredValues(uri, values); 605 } 606 607 public void testGroupsInsert() { 608 ContentValues values = new ContentValues(); 609 values.put(Groups.NAME, "Galois"); 610 values.put(Groups.NOTES, "Abel"); 611 values.put(Groups.SYSTEM_ID, "12345"); 612 613 Uri groupUri = mResolver.insert(Groups.CONTENT_URI, values); 614 assertStoredValues(groupUri, values); 615 } 616 617 public void testGroupsUpdate() { 618 ContentValues values = new ContentValues(); 619 values.put(Groups.NAME, "Galois"); 620 values.put(Groups.NOTES, "Abel"); 621 values.put(Groups.SYSTEM_ID, "12345"); 622 623 Uri groupUri = mResolver.insert(Groups.CONTENT_URI, values); 624 625 values.clear(); 626 values.put(Groups.NAME, "Klein"); 627 values.put(Groups.NOTES, "Vierergruppe"); 628 values.put(Groups.SYSTEM_ID, "1234"); 629 mResolver.update(groupUri, values, null, null); 630 assertStoredValues(groupUri, values); 631 } 632 633 public void testGroupMembershipsInsert() { 634 ContentValues values = new ContentValues(); 635 values.put(Groups.NOTES, "Abel"); 636 Uri groupUri = insertLegacyGroup("Galois", values); 637 Uri personUri = insertPerson("Klein", values); 638 Uri membershipUri = insertLegacyGroupMembership(groupUri, personUri, values); 639 assertStoredValues(membershipUri, values); 640 assertSelection(GroupMembership.CONTENT_URI, values, "groupmembership", 641 GroupMembership._ID, ContentUris.parseId(membershipUri)); 642 643 Uri personsGroupsUri = Uri.withAppendedPath(personUri, GroupMembership.CONTENT_DIRECTORY); 644 assertStoredValues(personsGroupsUri, values); 645 } 646 647 public void testAddToGroup() { 648 ContentValues values = new ContentValues(); 649 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 650 long personId = ContentUris.parseId(personUri); 651 652 values.clear(); 653 values.put(Groups.NAME, "Galois"); 654 Uri groupUri = mResolver.insert(Groups.CONTENT_URI, values); 655 656 People.addToGroup(mResolver, personId, "Galois"); 657 658 values.clear(); 659 values.put(GroupMembership.GROUP_ID, ContentUris.parseId(groupUri)); 660 values.put(GroupMembership.PERSON_ID, personId); 661 662 Uri personsGroupsUri = Uri.withAppendedPath(personUri, GroupMembership.CONTENT_DIRECTORY); 663 assertStoredValues(personsGroupsUri, values); 664 } 665 666 public void testGroupMembersByGroupName() { 667 ContentValues values = new ContentValues(); 668 Uri groupUri1 = insertLegacyGroup("Galois", values); 669 Uri personUri1 = insertPerson("Klein", values); 670 insertLegacyGroupMembership(groupUri1, personUri1, values); 671 672 Uri groupUri2 = insertLegacyGroup("Euler", values); 673 Uri personUri2 = insertPerson("Lagrange", values); 674 insertLegacyGroupMembership(groupUri2, personUri2, values); 675 676 // NOTE: testing non-public API support 677 assertStoredValue(Uri.parse("content://contacts/groups/name/Galois/members"), 678 People.NAME, "Klein"); 679 assertStoredValue(Uri.parse("content://contacts/groups/name/Euler/members"), 680 People.NAME, "Lagrange"); 681 } 682 683 public void testPhotoUpdate() throws Exception { 684 byte[] photo = loadTestPhoto(); 685 686 ContentValues values = new ContentValues(); 687 Uri personUri = mResolver.insert(People.CONTENT_URI, values); 688 689 values.clear(); 690 values.put(Photos.DATA, photo); 691 values.put(Photos.LOCAL_VERSION, "10"); 692 // FIXME this column was unavailable for update in legacy ContactsProvider 693 // values.put(Photos.DOWNLOAD_REQUIRED, 1); 694 values.put(Photos.EXISTS_ON_SERVER, 1); 695 values.put(Photos.SYNC_ERROR, "404 does not exist"); 696 697 Uri photoUri = Uri.withAppendedPath(personUri, Photos.CONTENT_DIRECTORY); 698 mResolver.update(photoUri, values, null, null); 699 assertStoredValues(photoUri, values); 700 701 long photoId = Long.parseLong(getStoredValue(photoUri, Photos._ID)); 702 703 values.put(Photos.LOCAL_VERSION, "11"); 704 Uri contentUri = ContentUris.withAppendedId(Photos.CONTENT_URI, photoId); 705 mResolver.update(contentUri, values, null, null); 706 assertStoredValues(contentUri, values); 707 assertStoredValues(photoUri, values); 708 } 709 710 /** 711 * Capturing the search suggestion requirements in test cases as a reference. 712 */ 713 public void testSearchSuggestionsNotInMyContacts() throws Exception { 714 715 // We don't provide compatibility for search suggestions 716 if (!USE_LEGACY_PROVIDER) { 717 return; 718 } 719 720 ContentValues values = new ContentValues(); 721 putContactValues(values); 722 mResolver.insert(People.CONTENT_URI, values); 723 724 Uri searchUri = new Uri.Builder().scheme("content").authority(Contacts.AUTHORITY) 725 .appendPath(SearchManager.SUGGEST_URI_PATH_QUERY).appendPath("D").build(); 726 727 // If the contact is not in the "my contacts" group, nothing should be found 728 Cursor c = mResolver.query(searchUri, null, null, null, null); 729 assertEquals(0, c.getCount()); 730 c.close(); 731 } 732 733 /** 734 * Capturing the search suggestion requirements in test cases as a reference. 735 */ 736 public void testSearchSuggestionsByName() throws Exception { 737 738 // We don't provide compatibility for search suggestions 739 if (!USE_LEGACY_PROVIDER) { 740 return; 741 } 742 743 assertSearchSuggestion( 744 true, // name 745 true, // photo 746 true, // organization 747 false, // phone 748 false, // email 749 "D", // query 750 true, // expect icon URI 751 null, "Deer Dough", "Google"); 752 753 assertSearchSuggestion( 754 true, // name 755 true, // photo 756 false, // organization 757 true, // phone 758 false, // email 759 "D", // query 760 true, // expect icon URI 761 null, "Deer Dough", "1-800-4664-411"); 762 763 assertSearchSuggestion( 764 true, // name 765 true, // photo 766 false, // organization 767 false, // phone 768 true, // email 769 "D", // query 770 true, // expect icon URI 771 String.valueOf(Presence.getPresenceIconResourceId(Presence.OFFLINE)), 772 "Deer Dough", "foo@acme.com"); 773 774 assertSearchSuggestion( 775 true, // name 776 false, // photo 777 true, // organization 778 false, // phone 779 false, // email 780 "D", // query 781 false, // expect icon URI 782 null, "Deer Dough", "Google"); 783 } 784 785 private void assertSearchSuggestion(boolean name, boolean photo, boolean organization, 786 boolean phone, boolean email, String query, boolean expectIcon1Uri, String expectedIcon2, 787 String expectedText1, String expectedText2) throws IOException { 788 ContentValues values = new ContentValues(); 789 790 if (name) { 791 values.put(People.NAME, "Deer Dough"); 792 } 793 794 final Uri personUri = mResolver.insert(People.CONTENT_URI, values); 795 long personId = ContentUris.parseId(personUri); 796 797 People.addToMyContactsGroup(mResolver, personId); 798 799 if (photo) { 800 values.clear(); 801 byte[] photoData = loadTestPhoto(); 802 values.put(Photos.DATA, photoData); 803 values.put(Photos.LOCAL_VERSION, "1"); 804 values.put(Photos.EXISTS_ON_SERVER, 0); 805 Uri photoUri = Uri.withAppendedPath(personUri, Photos.CONTENT_DIRECTORY); 806 mResolver.update(photoUri, values, null, null); 807 } 808 809 if (organization) { 810 values.clear(); 811 values.put(Organizations.ISPRIMARY, 1); 812 values.put(Organizations.COMPANY, "Google"); 813 values.put(Organizations.TYPE, Organizations.TYPE_WORK); 814 values.put(Organizations.PERSON_ID, personId); 815 mResolver.insert(Organizations.CONTENT_URI, values); 816 } 817 818 if (email) { 819 values.clear(); 820 values.put(ContactMethods.PERSON_ID, personId); 821 values.put(ContactMethods.KIND, Contacts.KIND_EMAIL); 822 values.put(ContactMethods.TYPE, ContactMethods.TYPE_HOME); 823 values.put(ContactMethods.DATA, "foo@acme.com"); 824 values.put(ContactMethods.ISPRIMARY, 1); 825 mResolver.insert(ContactMethods.CONTENT_URI, values); 826 827 828 String protocol = ContactMethods 829 .encodePredefinedImProtocol(ContactMethods.PROTOCOL_GOOGLE_TALK); 830 values.clear(); 831 values.put(Presence.IM_PROTOCOL, protocol); 832 values.put(Presence.IM_HANDLE, "foo@acme.com"); 833 values.put(Presence.IM_ACCOUNT, "foo"); 834 values.put(Presence.PRESENCE_STATUS, Presence.OFFLINE); 835 values.put(Presence.PRESENCE_CUSTOM_STATUS, "Coding for Android"); 836 mResolver.insert(Presence.CONTENT_URI, values); 837 } 838 839 if (phone) { 840 values.clear(); 841 values.put(Phones.PERSON_ID, personId); 842 values.put(Phones.TYPE, Phones.TYPE_HOME); 843 values.put(Phones.NUMBER, "1-800-4664-411"); 844 values.put(Phones.ISPRIMARY, 1); 845 mResolver.insert(Phones.CONTENT_URI, values); 846 } 847 848 Uri searchUri = new Uri.Builder().scheme("content").authority(Contacts.AUTHORITY) 849 .appendPath(SearchManager.SUGGEST_URI_PATH_QUERY).appendPath(query).build(); 850 851 Cursor c = mResolver.query(searchUri, null, null, null, null); 852 assertEquals(1, c.getCount()); 853 c.moveToFirst(); 854 values.clear(); 855 856 String icon1 = c.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1)); 857 if (expectIcon1Uri) { 858 assertTrue(icon1.startsWith("content:")); 859 } else { 860 assertEquals(String.valueOf(com.android.internal.R.drawable.ic_contact_picture), icon1); 861 } 862 863 // SearchManager does not declare a constant for _id 864 values.put("_id", personId); 865 values.put(SearchManager.SUGGEST_COLUMN_ICON_2, expectedIcon2); 866 values.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, personId); 867 values.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, personId); 868 values.put(SearchManager.SUGGEST_COLUMN_TEXT_1, expectedText1); 869 values.put(SearchManager.SUGGEST_COLUMN_TEXT_2, expectedText2); 870 assertCursorValues(c, values); 871 c.close(); 872 873 // Cleanup 874 mResolver.delete(personUri, null, null); 875 } 876 877 /** 878 * Capturing the search suggestion requirements in test cases as a reference. 879 */ 880 public void testSearchSuggestionsByPhoneNumber() throws Exception { 881 882 // We don't provide compatibility for search suggestions 883 if (!USE_LEGACY_PROVIDER) { 884 return; 885 } 886 887 ContentValues values = new ContentValues(); 888 889 Uri searchUri = new Uri.Builder().scheme("content").authority(Contacts.AUTHORITY) 890 .appendPath(SearchManager.SUGGEST_URI_PATH_QUERY).appendPath("12345").build(); 891 892 Cursor c = mResolver.query(searchUri, null, null, null, null); 893 assertEquals(2, c.getCount()); 894 c.moveToFirst(); 895 896 values.put(SearchManager.SUGGEST_COLUMN_TEXT_1, "Execute"); 897 values.put(SearchManager.SUGGEST_COLUMN_TEXT_2, ""); 898 values.put(SearchManager.SUGGEST_COLUMN_ICON_1, 899 String.valueOf(com.android.internal.R.drawable.call_contact)); 900 values.put(SearchManager.SUGGEST_COLUMN_INTENT_ACTION, 901 Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED); 902 values.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, "tel:12345"); 903 values.putNull(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID); 904 assertCursorValues(c, values); 905 906 c.moveToNext(); 907 values.clear(); 908 values.put(SearchManager.SUGGEST_COLUMN_TEXT_1, "Dial number"); 909 values.put(SearchManager.SUGGEST_COLUMN_TEXT_2, "using 12345"); 910 values.put(SearchManager.SUGGEST_COLUMN_ICON_1, 911 String.valueOf(com.android.internal.R.drawable.create_contact)); 912 values.put(SearchManager.SUGGEST_COLUMN_INTENT_ACTION, 913 Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED); 914 values.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, "tel:12345"); 915 values.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, 916 SearchManager.SUGGEST_NEVER_MAKE_SHORTCUT); 917 assertCursorValues(c, values); 918 c.close(); 919 } 920 921 private Uri insertPerson(String name, ContentValues values) { 922 values.put(People.NAME, name); 923 return mResolver.insert(People.CONTENT_URI, values); 924 } 925 926 private Uri insertLegacyGroup(String name, ContentValues values) { 927 values.put(Groups.NAME, name); 928 return mResolver.insert(Groups.CONTENT_URI, values); 929 } 930 931 private Uri insertLegacyGroupMembership(Uri groupUri, Uri personUri, ContentValues values) { 932 long groupId = ContentUris.parseId(groupUri); 933 long personId = ContentUris.parseId(personUri); 934 935 values.clear(); 936 values.put(GroupMembership.GROUP_ID, groupId); 937 values.put(GroupMembership.PERSON_ID, personId); 938 Uri membershipUri = mResolver.insert(GroupMembership.CONTENT_URI, values); 939 return membershipUri; 940 } 941 942 private void putContactValues(ContentValues values) { 943 putContactValuesExceptName(values); 944 values.put(People.NAME, "Deer Dough"); 945 } 946 947 private void putContactValuesExceptName(ContentValues values) { 948 // Populating only unhidden columns 949 values.put(People.PHONETIC_NAME, "Dear Doe"); 950 values.put(People.NOTES, "Cash Cow"); 951 values.put(People.TIMES_CONTACTED, 3); 952 values.put(People.LAST_TIME_CONTACTED, 10); 953 values.put(People.CUSTOM_RINGTONE, "ringtone"); 954 values.put(People.SEND_TO_VOICEMAIL, 1); 955 values.put(People.STARRED, 1); 956 } 957 958 private void putContactValues2(ContentValues values) { 959 // Populating only unhidden columns 960 values.put(People.NAME, "John Doe"); 961 values.put(People.PHONETIC_NAME, "jon dawe"); 962 values.put(People.NOTES, "Poor Johnny"); 963 values.put(People.TIMES_CONTACTED, 4); 964 values.put(People.LAST_TIME_CONTACTED, 11); 965 values.put(People.CUSTOM_RINGTONE, "rangtone"); 966 values.put(People.SEND_TO_VOICEMAIL, 0); 967 values.put(People.STARRED, 0); 968 } 969 970 private void assertFilteredContacts(String filter, String... expectedNames) { 971 Uri filterUri = Uri.withAppendedPath(People.CONTENT_FILTER_URI, filter); 972 Cursor c = mResolver.query(filterUri, null, null, null, null); 973 try { 974 assertEquals("Record count", expectedNames.length, c.getCount()); 975 int column = c.getColumnIndex(People.NAME); 976 for (int i = 0; i < expectedNames.length; i++) { 977 c.moveToNext(); 978 assertEquals(expectedNames[i], c.getString(column)); 979 } 980 } finally { 981 c.close(); 982 } 983 } 984 985 private void assertPersonIdConstraint(Uri uri, String typeColumn, int defaultType) { 986 ContentValues values = new ContentValues(); 987 values.put(typeColumn, defaultType); 988 try { 989 mResolver.insert(uri, values); 990 fail("Inserted row without person ID"); 991 } catch (Exception e) { 992 // Exception expected 993 } 994 } 995 996 private void assertTypeAndLabelConstraints(Uri uri, String personIdColumn, long personId, 997 String typeColumn, int defaultType, int otherType, String labelColumn) { 998 ContentValues values = new ContentValues(); 999 values.put(personIdColumn, personId); 1000 values.put(labelColumn, "Foo"); 1001 1002 try { 1003 mResolver.insert(uri, values); 1004 fail("Inserted row with label without defining type"); 1005 } catch (Exception e) { 1006 // Exception expected 1007 } 1008 } 1009 1010 protected void assertSelection(Uri uri, ContentValues values, String legacyTable, 1011 String idColumn, long id) { 1012 values.put(idColumn, id); 1013 String qualified = legacyTable + "." + idColumn; 1014 super.assertSelection(uri, values, qualified, id); 1015 } 1016} 1017