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