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