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 android.app.SearchManager; 20 import android.content.ContentProvider; 21 import android.content.ContentUris; 22 import android.content.ContentValues; 23 import android.database.Cursor; 24 import android.net.Uri; 25 import android.provider.Contacts; 26 import android.provider.Contacts.ContactMethods; 27 import android.provider.Contacts.Extensions; 28 import android.provider.Contacts.GroupMembership; 29 import android.provider.Contacts.Groups; 30 import android.provider.Contacts.Organizations; 31 import android.provider.Contacts.People; 32 import android.provider.Contacts.Phones; 33 import android.provider.Contacts.Photos; 34 import android.provider.Contacts.Presence; 35 import android.provider.Contacts.Settings; 36 import android.provider.ContactsContract; 37 import android.test.suitebuilder.annotation.MediumTest; 38 39 import 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") 55 public class LegacyContactsProviderTest extends BaseContactsProvider2Test { 56 57 @Override getProviderClass()58 protected Class<? extends ContentProvider> getProviderClass() { 59 return SynchronousContactsProvider2.class; 60 } 61 62 @Override getAuthority()63 protected String getAuthority() { 64 return Contacts.AUTHORITY + ";" + ContactsContract.AUTHORITY; 65 } 66 testPeopleInsert()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 testPeopleUpdate()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 testPeopleDelete()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 testPeopleFilter()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 testDefaultDisplayName()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 testPrimaryOrganization()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 testPrimaryPhone()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 testEmailCrud()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 testPrimaryEmail()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 testMarkAsContacted()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 testOrganizationsInsert()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 testOrganizationsUpdate()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 testPhonesInsert()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 testPhonesUpdate()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 testPhonesFilterQuery()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 testEmailInsert()480 public void testEmailInsert() { 481 assertContactMethodInsert(Contacts.KIND_EMAIL, 482 ContactMethods.TYPE_CUSTOM, "Some other way", "foo@acme.com", null, true); 483 } 484 testEmailUpdate()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 testImInsertStandard()491 public void testImInsertStandard() { 492 assertContactMethodInsert(Contacts.KIND_IM, 493 ContactMethods.TYPE_CUSTOM, "Some other way", "pre:3", "Bar", true); 494 } 495 testImUpdateStandard()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 testImInsertCustom()502 public void testImInsertCustom() { 503 assertContactMethodInsert(Contacts.KIND_IM, 504 ContactMethods.TYPE_CUSTOM, "Some other way", "custom:my_proto", "Bar", true); 505 } 506 testImUpdateCustom()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 testPostalInsert()513 public void testPostalInsert() { 514 assertContactMethodInsert(Contacts.KIND_POSTAL, 515 ContactMethods.TYPE_CUSTOM, "Some other way", "Foo", "Bar", true); 516 } 517 testPostalUpdate()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 assertContactMethodInsert(int kind, int type, String label, String data, String auxData, boolean primary)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 assertContactMethodUpdate(int kind, int type1, String label1, String data1, String auxData1, boolean primary1, int type2, String label2, String data2, String auxData2, boolean primary2)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 testExtensionsInsert()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 testExtensionsUpdate()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 testGroupsInsert()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 testGroupsUpdate()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 testGroupMembershipsInsert()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 testAddToGroup()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 testGroupMembersByGroupName()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 testPhotoUpdate()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 */ testSearchSuggestionsNotInMyContacts()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 */ testSearchSuggestionsByName()753 public void testSearchSuggestionsByName() throws Exception { 754 755 // We don't provide compatibility for search suggestions 756 return; 757 } 758 assertSearchSuggestion(boolean name, boolean photo, boolean organization, boolean phone, boolean email, String query, boolean expectIcon1Uri, String expectedIcon2, String expectedText1, String expectedText2)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 */ testSearchSuggestionsByPhoneNumber()854 public void testSearchSuggestionsByPhoneNumber() throws Exception { 855 // We don't provide compatibility for search suggestions 856 return; 857 } 858 testSettings()859 public void testSettings() throws Exception { 860 ContentValues values = new ContentValues(); 861 values.put(Settings._SYNC_ACCOUNT, "foo"); 862 values.put(Settings._SYNC_ACCOUNT_TYPE, "bar"); 863 values.put(Settings.KEY, Settings.SYNC_EVERYTHING); 864 values.put(Settings.VALUE, 7); 865 mResolver.update(Settings.CONTENT_URI, values, null, null); 866 867 assertStoredValue(Settings.CONTENT_URI, Settings._SYNC_ACCOUNT + "='foo' AND " 868 + Settings.KEY + "='" + Settings.SYNC_EVERYTHING + "'", null, Settings.VALUE, "7"); 869 870 assertStoredValue(ContactsContract.Settings.CONTENT_URI, 871 ContactsContract.Settings.ACCOUNT_NAME + "='foo'", 872 null, ContactsContract.Settings.SHOULD_SYNC, "7"); 873 874 values.clear(); 875 values.put(ContactsContract.Settings.SHOULD_SYNC, 8); 876 mResolver.update(ContactsContract.Settings.CONTENT_URI, values, 877 ContactsContract.Settings.ACCOUNT_NAME + "='foo'", null); 878 879 assertStoredValue(Settings.CONTENT_URI, Settings._SYNC_ACCOUNT + "='foo' AND " 880 + Settings.KEY + "='" + Settings.SYNC_EVERYTHING + "'", null, Settings.VALUE, "8"); 881 } 882 insertPerson(String name, ContentValues values)883 private Uri insertPerson(String name, ContentValues values) { 884 values.put(People.NAME, name); 885 return mResolver.insert(People.CONTENT_URI, values); 886 } 887 insertLegacyGroup(String name, ContentValues values)888 private Uri insertLegacyGroup(String name, ContentValues values) { 889 values.put(Groups.NAME, name); 890 return mResolver.insert(Groups.CONTENT_URI, values); 891 } 892 insertLegacyGroupMembership(Uri groupUri, Uri personUri, ContentValues values)893 private Uri insertLegacyGroupMembership(Uri groupUri, Uri personUri, ContentValues values) { 894 long groupId = ContentUris.parseId(groupUri); 895 long personId = ContentUris.parseId(personUri); 896 897 values.clear(); 898 values.put(GroupMembership.GROUP_ID, groupId); 899 values.put(GroupMembership.PERSON_ID, personId); 900 Uri membershipUri = mResolver.insert(GroupMembership.CONTENT_URI, values); 901 return membershipUri; 902 } 903 putContactValues(ContentValues values)904 private void putContactValues(ContentValues values) { 905 putContactValuesExceptName(values); 906 values.put(People.NAME, "Deer Dough"); 907 } 908 putContactValuesExceptName(ContentValues values)909 private void putContactValuesExceptName(ContentValues values) { 910 // Populating only unhidden columns 911 values.put(People.NOTES, "Cash Cow"); 912 values.put(People.TIMES_CONTACTED, 3); 913 values.put(People.LAST_TIME_CONTACTED, 10); 914 values.put(People.CUSTOM_RINGTONE, "ringtone"); 915 values.put(People.SEND_TO_VOICEMAIL, 1); 916 values.put(People.STARRED, 1); 917 } 918 putContactValues2(ContentValues values)919 private void putContactValues2(ContentValues values) { 920 // Populating only unhidden columns 921 values.put(People.NAME, "John Doe"); 922 values.put(People.PHONETIC_NAME, "jon dawe"); 923 values.put(People.NOTES, "Poor Johnny"); 924 values.put(People.TIMES_CONTACTED, 4); 925 values.put(People.LAST_TIME_CONTACTED, 11); 926 values.put(People.CUSTOM_RINGTONE, "rangtone"); 927 values.put(People.SEND_TO_VOICEMAIL, 0); 928 values.put(People.STARRED, 0); 929 } 930 assertFilteredContacts(String filter, String... expectedNames)931 private void assertFilteredContacts(String filter, String... expectedNames) { 932 Uri filterUri = Uri.withAppendedPath(People.CONTENT_FILTER_URI, filter); 933 Cursor c = mResolver.query(filterUri, null, null, null, null); 934 try { 935 assertEquals("Record count", expectedNames.length, c.getCount()); 936 int column = c.getColumnIndex(People.NAME); 937 for (int i = 0; i < expectedNames.length; i++) { 938 c.moveToNext(); 939 assertEquals(expectedNames[i], c.getString(column)); 940 } 941 } finally { 942 c.close(); 943 } 944 } 945 assertPersonIdConstraint(Uri uri, String typeColumn, int defaultType)946 private void assertPersonIdConstraint(Uri uri, String typeColumn, int defaultType) { 947 ContentValues values = new ContentValues(); 948 values.put(typeColumn, defaultType); 949 try { 950 mResolver.insert(uri, values); 951 fail("Inserted row without person ID"); 952 } catch (Exception e) { 953 // Exception expected 954 } 955 } 956 assertTypeAndLabelConstraints(Uri uri, String personIdColumn, long personId, String typeColumn, int defaultType, int otherType, String labelColumn)957 private void assertTypeAndLabelConstraints(Uri uri, String personIdColumn, long personId, 958 String typeColumn, int defaultType, int otherType, String labelColumn) { 959 ContentValues values = new ContentValues(); 960 values.put(personIdColumn, personId); 961 values.put(labelColumn, "Foo"); 962 963 try { 964 mResolver.insert(uri, values); 965 fail("Inserted row with label without defining type"); 966 } catch (Exception e) { 967 // Exception expected 968 } 969 } 970 assertSelection(Uri uri, ContentValues values, String legacyTable, String idColumn, long id)971 protected void assertSelection(Uri uri, ContentValues values, String legacyTable, 972 String idColumn, long id) { 973 values.put(idColumn, id); 974 String qualified = legacyTable + "." + idColumn; 975 super.assertSelection(uri, values, qualified, id); 976 } 977 } 978