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