Home | History | Annotate | Download | only in contacts
      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