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