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 getProviderClass()61 protected Class<? extends ContentProvider> getProviderClass() { 62 return SynchronousContactsProvider2.class; 63 } 64 65 @Override getAuthority()66 protected String getAuthority() { 67 return Contacts.AUTHORITY + ";" + ContactsContract.AUTHORITY; 68 } 69 noStats(ContentValues v)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 testPeopleInsert()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 testPeopleUpdate()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 testPeopleDelete()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 testPeopleFilter()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 testDefaultDisplayName()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 testPrimaryOrganization()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 testPrimaryPhone()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 testEmailCrud()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@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 testPrimaryEmail()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@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@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@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@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 testMarkAsContacted()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 testOrganizationsInsert()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 testOrganizationsUpdate()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 testPhonesInsert()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 testPhonesUpdate()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 testPhonesFilterQuery()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 testEmailInsert()501 public void testEmailInsert() { 502 assertContactMethodInsert(Contacts.KIND_EMAIL, 503 ContactMethods.TYPE_CUSTOM, "Some other way", "foo@acme.com", null, true); 504 } 505 testEmailUpdate()506 public void testEmailUpdate() { 507 assertContactMethodUpdate(Contacts.KIND_EMAIL, 508 ContactMethods.TYPE_CUSTOM, "Some other way", "foo@acme.com", null, false, 509 ContactMethods.TYPE_HOME, null, "bar@acme.com", "aux", true); 510 } 511 testImInsertStandard()512 public void testImInsertStandard() { 513 assertContactMethodInsert(Contacts.KIND_IM, 514 ContactMethods.TYPE_CUSTOM, "Some other way", "pre:3", "Bar", true); 515 } 516 testImUpdateStandard()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 testImInsertCustom()523 public void testImInsertCustom() { 524 assertContactMethodInsert(Contacts.KIND_IM, 525 ContactMethods.TYPE_CUSTOM, "Some other way", "custom:my_proto", "Bar", true); 526 } 527 testImUpdateCustom()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 testPostalInsert()534 public void testPostalInsert() { 535 assertContactMethodInsert(Contacts.KIND_POSTAL, 536 ContactMethods.TYPE_CUSTOM, "Some other way", "Foo", "Bar", true); 537 } 538 testPostalUpdate()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 assertContactMethodInsert(int kind, int type, String label, String data, String auxData, boolean primary)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 assertContactMethodUpdate(int kind, int type1, String label1, String data1, String auxData1, boolean primary1, int type2, String label2, String data2, String auxData2, boolean primary2)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 testExtensionsInsert()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 testExtensionsUpdate()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 testGroupsInsert()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 testGroupsUpdate()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 testGroupMembershipsInsert()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 testAddToGroup()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 testGroupMembersByGroupName()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 testPhotoUpdate()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 */ testSearchSuggestionsNotInMyContacts()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 */ testSearchSuggestionsByName()777 public void testSearchSuggestionsByName() throws Exception { 778 779 // We don't provide compatibility for search suggestions 780 return; 781 } 782 assertSearchSuggestion(boolean name, boolean photo, boolean organization, boolean phone, boolean email, String query, boolean expectIcon1Uri, String expectedIcon2, String expectedText1, String expectedText2)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@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@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 */ testSearchSuggestionsByPhoneNumber()878 public void testSearchSuggestionsByPhoneNumber() throws Exception { 879 // We don't provide compatibility for search suggestions 880 return; 881 } 882 testSettings()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 insertPerson(String name, ContentValues values)907 private Uri insertPerson(String name, ContentValues values) { 908 values.put(People.NAME, name); 909 return mResolver.insert(People.CONTENT_URI, values); 910 } 911 insertLegacyGroup(String name, ContentValues values)912 private Uri insertLegacyGroup(String name, ContentValues values) { 913 values.put(Groups.NAME, name); 914 return mResolver.insert(Groups.CONTENT_URI, values); 915 } 916 insertLegacyGroupMembership(Uri groupUri, Uri personUri, ContentValues values)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 putContactValues(ContentValues values)928 private void putContactValues(ContentValues values) { 929 putContactValuesExceptName(values); 930 values.put(People.NAME, "Deer Dough"); 931 } 932 putContactValuesExceptName(ContentValues values)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 putContactValues2(ContentValues values)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 assertFilteredContacts(String filter, String... expectedNames)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 assertPersonIdConstraint(Uri uri, String typeColumn, int defaultType)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 assertTypeAndLabelConstraints(Uri uri, String personIdColumn, long personId, String typeColumn, int defaultType, int otherType, String labelColumn)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 assertSelection(Uri uri, ContentValues values, String legacyTable, String idColumn, long id)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