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 com.android.internal.util.ArrayUtils;
     20 import com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns;
     21 import com.google.android.collect.Lists;
     22 
     23 import android.accounts.Account;
     24 import android.content.ContentProviderOperation;
     25 import android.content.ContentProviderResult;
     26 import android.content.ContentUris;
     27 import android.content.ContentValues;
     28 import android.content.Entity;
     29 import android.content.EntityIterator;
     30 import android.content.res.AssetFileDescriptor;
     31 import android.database.Cursor;
     32 import android.net.Uri;
     33 import android.os.RemoteException;
     34 import android.provider.ContactsContract;
     35 import android.provider.LiveFolders;
     36 import android.provider.OpenableColumns;
     37 import android.provider.ContactsContract.AggregationExceptions;
     38 import android.provider.ContactsContract.ContactCounts;
     39 import android.provider.ContactsContract.Contacts;
     40 import android.provider.ContactsContract.Data;
     41 import android.provider.ContactsContract.DisplayNameSources;
     42 import android.provider.ContactsContract.Groups;
     43 import android.provider.ContactsContract.PhoneLookup;
     44 import android.provider.ContactsContract.PhoneticNameStyle;
     45 import android.provider.ContactsContract.ProviderStatus;
     46 import android.provider.ContactsContract.RawContacts;
     47 import android.provider.ContactsContract.RawContactsEntity;
     48 import android.provider.ContactsContract.SearchSnippetColumns;
     49 import android.provider.ContactsContract.Settings;
     50 import android.provider.ContactsContract.StatusUpdates;
     51 import android.provider.ContactsContract.CommonDataKinds.Email;
     52 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
     53 import android.provider.ContactsContract.CommonDataKinds.Im;
     54 import android.provider.ContactsContract.CommonDataKinds.Nickname;
     55 import android.provider.ContactsContract.CommonDataKinds.Organization;
     56 import android.provider.ContactsContract.CommonDataKinds.Phone;
     57 import android.provider.ContactsContract.CommonDataKinds.Photo;
     58 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
     59 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
     60 import android.test.MoreAsserts;
     61 import android.test.suitebuilder.annotation.LargeTest;
     62 
     63 import java.io.FileInputStream;
     64 import java.io.IOException;
     65 import java.text.Collator;
     66 import java.util.Arrays;
     67 import java.util.Locale;
     68 
     69 
     70 /**
     71  * Unit tests for {@link ContactsProvider2}.
     72  *
     73  * Run the test like this:
     74  * <code>
     75  * adb shell am instrument -e class com.android.providers.contacts.ContactsProvider2Test -w \
     76  *         com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
     77  * </code>
     78  */
     79 @LargeTest
     80 public class ContactsProvider2Test extends BaseContactsProvider2Test {
     81 
     82     public void testRawContactsInsert() {
     83         ContentValues values = new ContentValues();
     84 
     85         values.put(RawContacts.ACCOUNT_NAME, "a");
     86         values.put(RawContacts.ACCOUNT_TYPE, "b");
     87         values.put(RawContacts.SOURCE_ID, "c");
     88         values.put(RawContacts.VERSION, 42);
     89         values.put(RawContacts.DIRTY, 1);
     90         values.put(RawContacts.DELETED, 1);
     91         values.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
     92         values.put(RawContacts.CUSTOM_RINGTONE, "d");
     93         values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
     94         values.put(RawContacts.LAST_TIME_CONTACTED, 12345);
     95         values.put(RawContacts.STARRED, 1);
     96         values.put(RawContacts.SYNC1, "e");
     97         values.put(RawContacts.SYNC2, "f");
     98         values.put(RawContacts.SYNC3, "g");
     99         values.put(RawContacts.SYNC4, "h");
    100 
    101         Uri rowUri = mResolver.insert(RawContacts.CONTENT_URI, values);
    102         long rawContactId = ContentUris.parseId(rowUri);
    103 
    104         assertStoredValues(rowUri, values);
    105         assertSelection(RawContacts.CONTENT_URI, values, RawContacts._ID, rawContactId);
    106         assertNetworkNotified(true);
    107     }
    108 
    109     public void testDataInsert() {
    110         long rawContactId = createRawContactWithName("John", "Doe");
    111 
    112         ContentValues values = new ContentValues();
    113         putDataValues(values, rawContactId);
    114         Uri dataUri = mResolver.insert(Data.CONTENT_URI, values);
    115         long dataId = ContentUris.parseId(dataUri);
    116 
    117         long contactId = queryContactId(rawContactId);
    118         values.put(RawContacts.CONTACT_ID, contactId);
    119         assertStoredValues(dataUri, values);
    120 
    121         assertSelection(Data.CONTENT_URI, values, Data._ID, dataId);
    122 
    123         // Access the same data through the directory under RawContacts
    124         Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
    125         Uri rawContactDataUri =
    126                 Uri.withAppendedPath(rawContactUri, RawContacts.Data.CONTENT_DIRECTORY);
    127         assertSelection(rawContactDataUri, values, Data._ID, dataId);
    128 
    129         // Access the same data through the directory under Contacts
    130         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
    131         Uri contactDataUri = Uri.withAppendedPath(contactUri, Contacts.Data.CONTENT_DIRECTORY);
    132         assertSelection(contactDataUri, values, Data._ID, dataId);
    133         assertNetworkNotified(true);
    134     }
    135 
    136     public void testRawContactDataQuery() {
    137         Account account1 = new Account("a", "b");
    138         Account account2 = new Account("c", "d");
    139         long rawContactId1 = createRawContact(account1);
    140         Uri dataUri1 = insertStructuredName(rawContactId1, "John", "Doe");
    141         long rawContactId2 = createRawContact(account2);
    142         Uri dataUri2 = insertStructuredName(rawContactId2, "Jane", "Doe");
    143 
    144         Uri uri1 = maybeAddAccountQueryParameters(dataUri1, account1);
    145         Uri uri2 = maybeAddAccountQueryParameters(dataUri2, account2);
    146         assertStoredValue(uri1, Data._ID, ContentUris.parseId(dataUri1)) ;
    147         assertStoredValue(uri2, Data._ID, ContentUris.parseId(dataUri2)) ;
    148     }
    149 
    150     public void testPhonesQuery() {
    151 
    152         ContentValues values = new ContentValues();
    153         values.put(RawContacts.CUSTOM_RINGTONE, "d");
    154         values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
    155         values.put(RawContacts.LAST_TIME_CONTACTED, 12345);
    156         values.put(RawContacts.TIMES_CONTACTED, 54321);
    157         values.put(RawContacts.STARRED, 1);
    158 
    159         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
    160         long rawContactId = ContentUris.parseId(rawContactUri);
    161 
    162         insertStructuredName(rawContactId, "Meghan", "Knox");
    163         Uri uri = insertPhoneNumber(rawContactId, "18004664411");
    164         long phoneId = ContentUris.parseId(uri);
    165 
    166 
    167         long contactId = queryContactId(rawContactId);
    168         values.clear();
    169         values.put(Data._ID, phoneId);
    170         values.put(Data.RAW_CONTACT_ID, rawContactId);
    171         values.put(RawContacts.CONTACT_ID, contactId);
    172         values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
    173         values.put(Phone.NUMBER, "18004664411");
    174         values.put(Phone.TYPE, Phone.TYPE_HOME);
    175         values.putNull(Phone.LABEL);
    176         values.put(Contacts.DISPLAY_NAME, "Meghan Knox");
    177         values.put(Contacts.CUSTOM_RINGTONE, "d");
    178         values.put(Contacts.SEND_TO_VOICEMAIL, 1);
    179         values.put(Contacts.LAST_TIME_CONTACTED, 12345);
    180         values.put(Contacts.TIMES_CONTACTED, 54321);
    181         values.put(Contacts.STARRED, 1);
    182 
    183         assertStoredValues(ContentUris.withAppendedId(Phone.CONTENT_URI, phoneId), values);
    184         assertSelection(Phone.CONTENT_URI, values, Data._ID, phoneId);
    185     }
    186 
    187     public void testPhonesFilterQuery() {
    188         long rawContactId1 = createRawContactWithName("Hot", "Tamale");
    189         insertPhoneNumber(rawContactId1, "18004664411");
    190         insertPhoneNumber(rawContactId1, "1-800-466-4411");
    191 
    192         long rawContactId2 = createRawContactWithName("Hot", "Tamale");
    193         insertPhoneNumber(rawContactId2, "1-800-466-4411");
    194 
    195         Uri filterUri1 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "tamale");
    196         ContentValues values = new ContentValues();
    197         values.put(Contacts.DISPLAY_NAME, "Hot Tamale");
    198         values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
    199         values.put(Phone.NUMBER, "1-800-466-4411");
    200         values.put(Phone.TYPE, Phone.TYPE_HOME);
    201         values.putNull(Phone.LABEL);
    202         assertStoredValuesWithProjection(filterUri1, values);
    203 
    204         Uri filterUri2 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "1-800-GOOG-411");
    205         assertStoredValues(filterUri2, values);
    206 
    207         Uri filterUri3 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "18004664");
    208         assertStoredValues(filterUri3, values);
    209 
    210         Uri filterUri4 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "encilada");
    211         assertEquals(0, getCount(filterUri4, null, null));
    212 
    213         Uri filterUri5 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "*");
    214         assertEquals(0, getCount(filterUri5, null, null));
    215     }
    216 
    217     public void testPhoneLookup() {
    218         ContentValues values = new ContentValues();
    219         values.put(RawContacts.CUSTOM_RINGTONE, "d");
    220         values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
    221 
    222         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
    223         long rawContactId = ContentUris.parseId(rawContactUri);
    224 
    225         insertStructuredName(rawContactId, "Hot", "Tamale");
    226         insertPhoneNumber(rawContactId, "18004664411");
    227 
    228         Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411");
    229 
    230         values.clear();
    231         values.put(PhoneLookup._ID, queryContactId(rawContactId));
    232         values.put(PhoneLookup.DISPLAY_NAME, "Hot Tamale");
    233         values.put(PhoneLookup.NUMBER, "18004664411");
    234         values.put(PhoneLookup.TYPE, Phone.TYPE_HOME);
    235         values.putNull(PhoneLookup.LABEL);
    236         values.put(PhoneLookup.CUSTOM_RINGTONE, "d");
    237         values.put(PhoneLookup.SEND_TO_VOICEMAIL, 1);
    238         assertStoredValues(lookupUri1, values);
    239 
    240         // The strict comparation, adopted in Donut, does not allow the behavior like
    241         // "8004664411 == 4664411", while the loose comparation, which had been used in Cupcake
    242         // and reverted back into the default in Eclair, allows it. Hmm...
    243         final boolean useStrictComparation =
    244             mContext.getResources().getBoolean(
    245                     com.android.internal.R.bool.config_use_strict_phone_number_comparation);
    246         final int expectedResult = (useStrictComparation ? 0 : 1);
    247 
    248         Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "4664411");
    249         assertEquals(expectedResult, getCount(lookupUri2, null, null));
    250     }
    251 
    252     public void testPhoneUpdate() {
    253         ContentValues values = new ContentValues();
    254         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
    255         long rawContactId = ContentUris.parseId(rawContactUri);
    256 
    257         insertStructuredName(rawContactId, "Hot", "Tamale");
    258         Uri phoneUri = insertPhoneNumber(rawContactId, "18004664411");
    259 
    260         Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411");
    261         assertStoredValue(lookupUri1, PhoneLookup.DISPLAY_NAME, "Hot Tamale");
    262 
    263         values.clear();
    264         values.put(Phone.NUMBER, "18004664422");
    265         mResolver.update(phoneUri, values, null, null);
    266 
    267         Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664422");
    268         assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale");
    269 
    270         // Setting number to null will remove the phone lookup record
    271         values.clear();
    272         values.putNull(Phone.NUMBER);
    273         mResolver.update(phoneUri, values, null, null);
    274 
    275         assertEquals(0, getCount(lookupUri2, null, null));
    276 
    277         // Let's restore that phone lookup record
    278         values.clear();
    279         values.put(Phone.NUMBER, "18004664422");
    280         mResolver.update(phoneUri, values, null, null);
    281         assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale");
    282         assertNetworkNotified(true);
    283     }
    284 
    285     public void testEmailsQuery() {
    286         ContentValues values = new ContentValues();
    287         values.put(RawContacts.CUSTOM_RINGTONE, "d");
    288         values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
    289         values.put(RawContacts.LAST_TIME_CONTACTED, 12345);
    290         values.put(RawContacts.TIMES_CONTACTED, 54321);
    291         values.put(RawContacts.STARRED, 1);
    292 
    293         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
    294         long rawContactId = ContentUris.parseId(rawContactUri);
    295 
    296         insertStructuredName(rawContactId, "Meghan", "Knox");
    297         Uri uri = insertEmail(rawContactId, "meghan (at) acme.com");
    298         long emailId = ContentUris.parseId(uri);
    299 
    300         long contactId = queryContactId(rawContactId);
    301         values.clear();
    302         values.put(Data._ID, emailId);
    303         values.put(Data.RAW_CONTACT_ID, rawContactId);
    304         values.put(RawContacts.CONTACT_ID, contactId);
    305         values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
    306         values.put(Email.DATA, "meghan (at) acme.com");
    307         values.put(Email.TYPE, Email.TYPE_HOME);
    308         values.putNull(Email.LABEL);
    309         values.put(Contacts.DISPLAY_NAME, "Meghan Knox");
    310         values.put(Contacts.CUSTOM_RINGTONE, "d");
    311         values.put(Contacts.SEND_TO_VOICEMAIL, 1);
    312         values.put(Contacts.LAST_TIME_CONTACTED, 12345);
    313         values.put(Contacts.TIMES_CONTACTED, 54321);
    314         values.put(Contacts.STARRED, 1);
    315 
    316         assertStoredValues(ContentUris.withAppendedId(Email.CONTENT_URI, emailId), values);
    317         assertSelection(Email.CONTENT_URI, values, Data._ID, emailId);
    318     }
    319 
    320     public void testEmailsLookupQuery() {
    321         long rawContactId = createRawContactWithName("Hot", "Tamale");
    322         insertEmail(rawContactId, "tamale (at) acme.com");
    323 
    324         Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "tamale (at) acme.com");
    325         ContentValues values = new ContentValues();
    326         values.put(Contacts.DISPLAY_NAME, "Hot Tamale");
    327         values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
    328         values.put(Email.DATA, "tamale (at) acme.com");
    329         values.put(Email.TYPE, Email.TYPE_HOME);
    330         values.putNull(Email.LABEL);
    331         assertStoredValues(filterUri1, values);
    332 
    333         Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "Ta<TaMale (at) acme.com>");
    334         assertStoredValues(filterUri2, values);
    335 
    336         Uri filterUri3 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "encilada (at) acme.com");
    337         assertEquals(0, getCount(filterUri3, null, null));
    338     }
    339 
    340     public void testEmailsFilterQuery() {
    341         long rawContactId1 = createRawContactWithName("Hot", "Tamale");
    342         insertEmail(rawContactId1, "tamale (at) acme.com");
    343         insertEmail(rawContactId1, "tamale (at) acme.com");
    344 
    345         long rawContactId2 = createRawContactWithName("Hot", "Tamale");
    346         insertEmail(rawContactId2, "tamale (at) acme.com");
    347 
    348         Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tam");
    349         ContentValues values = new ContentValues();
    350         values.put(Contacts.DISPLAY_NAME, "Hot Tamale");
    351         values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
    352         values.put(Email.DATA, "tamale (at) acme.com");
    353         values.put(Email.TYPE, Email.TYPE_HOME);
    354         values.putNull(Email.LABEL);
    355         assertStoredValuesWithProjection(filterUri1, values);
    356 
    357         Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hot");
    358         assertStoredValuesWithProjection(filterUri2, values);
    359 
    360         Uri filterUri3 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hottamale");
    361         assertStoredValuesWithProjection(filterUri3, values);
    362 
    363         Uri filterUri4 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tamale@acme");
    364         assertStoredValuesWithProjection(filterUri4, values);
    365 
    366         Uri filterUri5 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "encilada");
    367         assertEquals(0, getCount(filterUri5, null, null));
    368     }
    369 
    370     public void testPostalsQuery() {
    371         long rawContactId = createRawContactWithName("Alice", "Nextore");
    372         Uri dataUri = insertPostalAddress(rawContactId, "1600 Amphiteatre Ave, Mountain View");
    373         long dataId = ContentUris.parseId(dataUri);
    374 
    375         long contactId = queryContactId(rawContactId);
    376         ContentValues values = new ContentValues();
    377         values.put(Data._ID, dataId);
    378         values.put(Data.RAW_CONTACT_ID, rawContactId);
    379         values.put(RawContacts.CONTACT_ID, contactId);
    380         values.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
    381         values.put(StructuredPostal.FORMATTED_ADDRESS, "1600 Amphiteatre Ave, Mountain View");
    382         values.put(Contacts.DISPLAY_NAME, "Alice Nextore");
    383 
    384         assertStoredValues(ContentUris.withAppendedId(StructuredPostal.CONTENT_URI, dataId),
    385                 values);
    386         assertSelection(StructuredPostal.CONTENT_URI, values, Data._ID, dataId);
    387     }
    388 
    389     public void testQueryContactData() {
    390         ContentValues values = new ContentValues();
    391         long contactId = createContact(values, "John", "Doe",
    392                 "18004664411", "goog411 (at) acme.com", StatusUpdates.INVISIBLE, 4, 1, 0);
    393         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
    394 
    395         assertStoredValues(contactUri, values);
    396         assertSelection(Contacts.CONTENT_URI, values, Contacts._ID, contactId);
    397     }
    398 
    399     public void testQueryContactWithStatusUpdate() {
    400         ContentValues values = new ContentValues();
    401         long contactId = createContact(values, "John", "Doe",
    402                 "18004664411", "goog411 (at) acme.com", StatusUpdates.INVISIBLE, 4, 1, 0);
    403         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
    404         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
    405         assertStoredValuesWithProjection(contactUri, values);
    406         assertSelectionWithProjection(Contacts.CONTENT_URI, values, Contacts._ID, contactId);
    407     }
    408 
    409     public void testQueryContactFilter() {
    410         ContentValues values = new ContentValues();
    411         long rawContactId = createRawContact(values, "18004664411",
    412                 "goog411 (at) acme.com", StatusUpdates.INVISIBLE, 4, 1, 0);
    413 
    414         ContentValues nameValues = new ContentValues();
    415         nameValues.put(StructuredName.GIVEN_NAME, "Stu");
    416         nameValues.put(StructuredName.FAMILY_NAME, "Goulash");
    417         nameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "goo");
    418         nameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "LASH");
    419         Uri nameUri = insertStructuredName(rawContactId, nameValues);
    420 
    421         long contactId = queryContactId(rawContactId);
    422         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
    423 
    424         Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goulash");
    425         assertStoredValuesWithProjection(filterUri1, values);
    426 
    427         assertContactFilter(contactId, "goolash");
    428         assertContactFilter(contactId, "lash");
    429 
    430         Uri filterUri2 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goolish");
    431         assertEquals(0, getCount(filterUri2, null, null));
    432 
    433         // Phonetic name with given/family reversed should not match
    434         Uri filterUri3 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "lashgoo");
    435         assertEquals(0, getCount(filterUri3, null, null));
    436 
    437         nameValues.clear();
    438         nameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "ga");
    439         nameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "losh");
    440 
    441         mResolver.update(nameUri, nameValues, null, null);
    442 
    443         assertContactFilter(contactId, "galosh");
    444 
    445         Uri filterUri4 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goolish");
    446         assertEquals(0, getCount(filterUri4, null, null));
    447     }
    448 
    449     public void testQueryContactStrequent() {
    450         ContentValues values1 = new ContentValues();
    451         createContact(values1, "Noah", "Tever", "18004664411",
    452                 "a (at) acme.com", StatusUpdates.OFFLINE, 0, 0, 0);
    453         ContentValues values2 = new ContentValues();
    454         createContact(values2, "Sam", "Times", "18004664412",
    455                 "b (at) acme.com", StatusUpdates.INVISIBLE, 3, 0, 0);
    456         ContentValues values3 = new ContentValues();
    457         createContact(values3, "Lotta", "Calling", "18004664413",
    458                 "c (at) acme.com", StatusUpdates.AWAY, 5, 0, 0);
    459         ContentValues values4 = new ContentValues();
    460         createContact(values4, "Fay", "Veritt", "18004664414",
    461                 "d (at) acme.com", StatusUpdates.AVAILABLE, 0, 1, 0);
    462 
    463         Cursor c = mResolver.query(Contacts.CONTENT_STREQUENT_URI, null, null, null,
    464                 Contacts._ID);
    465         assertEquals(3, c.getCount());
    466         c.moveToFirst();
    467         assertCursorValues(c, values4);
    468         c.moveToNext();
    469         assertCursorValues(c, values3);
    470         c.moveToNext();
    471         assertCursorValues(c, values2);
    472         c.close();
    473 
    474         Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_STREQUENT_FILTER_URI, "fay");
    475         c = mResolver.query(filterUri, null, null, null, Contacts._ID);
    476         assertEquals(1, c.getCount());
    477         c.moveToFirst();
    478         assertCursorValues(c, values4);
    479         c.close();
    480     }
    481 
    482     public void testQueryContactGroup() {
    483         long groupId = createGroup(null, "testGroup", "Test Group");
    484 
    485         ContentValues values1 = new ContentValues();
    486         createContact(values1, "Best", "West", "18004664411",
    487                 "west (at) acme.com", StatusUpdates.OFFLINE, 0, 0, groupId);
    488 
    489         ContentValues values2 = new ContentValues();
    490         createContact(values2, "Rest", "East", "18004664422",
    491                 "east (at) acme.com", StatusUpdates.AVAILABLE, 0, 0, 0);
    492 
    493         Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group");
    494         Cursor c = mResolver.query(filterUri1, null, null, null, Contacts._ID);
    495         assertEquals(1, c.getCount());
    496         c.moveToFirst();
    497         assertCursorValues(c, values1);
    498         c.close();
    499 
    500         Uri filterUri2 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group");
    501         c = mResolver.query(filterUri2, null, Contacts.DISPLAY_NAME + "=?",
    502                 new String[] { "Best West" }, Contacts._ID);
    503         assertEquals(1, c.getCount());
    504         c.close();
    505 
    506         Uri filterUri3 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Next Group");
    507         c = mResolver.query(filterUri3, null, null, null, Contacts._ID);
    508         assertEquals(0, c.getCount());
    509         c.close();
    510     }
    511 
    512     public void testPhonesWithStatusUpdate() {
    513 
    514         ContentValues values = new ContentValues();
    515         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
    516         long rawContactId = ContentUris.parseId(rawContactUri);
    517         insertStructuredName(rawContactId, "John", "Doe");
    518         Uri photoUri = insertPhoto(rawContactId);
    519         long photoId = ContentUris.parseId(photoUri);
    520         values.put(Contacts.PHOTO_ID, photoId);
    521         insertPhoneNumber(rawContactId, "18004664411");
    522         insertPhoneNumber(rawContactId, "18004664412");
    523         insertEmail(rawContactId, "goog411 (at) acme.com");
    524         insertEmail(rawContactId, "goog412 (at) acme.com");
    525 
    526         insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog411 (at) acme.com",
    527                 StatusUpdates.INVISIBLE, "Bad");
    528         insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog412 (at) acme.com",
    529                 StatusUpdates.AVAILABLE, "Good");
    530         long contactId = queryContactId(rawContactId);
    531 
    532         Uri uri = Data.CONTENT_URI;
    533 
    534         Cursor c = mResolver.query(uri, null, RawContacts.CONTACT_ID + "=" + contactId + " AND "
    535                 + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'", null, Phone.NUMBER);
    536         assertEquals(2, c.getCount());
    537 
    538         c.moveToFirst();
    539 
    540         values.clear();
    541         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE);
    542         values.put(Contacts.CONTACT_STATUS, "Bad");
    543         values.put(Contacts.DISPLAY_NAME, "John Doe");
    544         values.put(Phone.NUMBER, "18004664411");
    545         values.putNull(Phone.LABEL);
    546         values.put(RawContacts.CONTACT_ID, contactId);
    547         assertCursorValues(c, values);
    548 
    549         c.moveToNext();
    550 
    551         values.clear();
    552         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE);
    553         values.put(Contacts.CONTACT_STATUS, "Bad");
    554         values.put(Contacts.DISPLAY_NAME, "John Doe");
    555         values.put(Phone.NUMBER, "18004664412");
    556         values.putNull(Phone.LABEL);
    557         values.put(RawContacts.CONTACT_ID, contactId);
    558         assertCursorValues(c, values);
    559 
    560         c.close();
    561     }
    562 
    563     public void testGroupQuery() {
    564         Account account1 = new Account("a", "b");
    565         Account account2 = new Account("c", "d");
    566         long groupId1 = createGroup(account1, "e", "f");
    567         long groupId2 = createGroup(account2, "g", "h");
    568         Uri uri1 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account1);
    569         Uri uri2 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account2);
    570         assertEquals(1, getCount(uri1, null, null));
    571         assertEquals(1, getCount(uri2, null, null));
    572         assertStoredValue(uri1, Groups._ID + "=" + groupId1, null, Groups._ID, groupId1) ;
    573         assertStoredValue(uri2, Groups._ID + "=" + groupId2, null, Groups._ID, groupId2) ;
    574     }
    575 
    576     public void testGroupInsert() {
    577         ContentValues values = new ContentValues();
    578 
    579         values.put(Groups.ACCOUNT_NAME, "a");
    580         values.put(Groups.ACCOUNT_TYPE, "b");
    581         values.put(Groups.SOURCE_ID, "c");
    582         values.put(Groups.VERSION, 42);
    583         values.put(Groups.GROUP_VISIBLE, 1);
    584         values.put(Groups.TITLE, "d");
    585         values.put(Groups.TITLE_RES, 1234);
    586         values.put(Groups.NOTES, "e");
    587         values.put(Groups.RES_PACKAGE, "f");
    588         values.put(Groups.SYSTEM_ID, "g");
    589         values.put(Groups.DELETED, 1);
    590         values.put(Groups.SYNC1, "h");
    591         values.put(Groups.SYNC2, "i");
    592         values.put(Groups.SYNC3, "j");
    593         values.put(Groups.SYNC4, "k");
    594 
    595         Uri rowUri = mResolver.insert(Groups.CONTENT_URI, values);
    596 
    597         values.put(Groups.DIRTY, 1);
    598         assertStoredValues(rowUri, values);
    599     }
    600 
    601     public void testSettingsQuery() {
    602         Account account1 = new Account("a", "b");
    603         Account account2 = new Account("c", "d");
    604         createSettings(account1, "0", "0");
    605         createSettings(account2, "1", "1");
    606         Uri uri1 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account1);
    607         Uri uri2 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account2);
    608         assertEquals(1, getCount(uri1, null, null));
    609         assertEquals(1, getCount(uri2, null, null));
    610         assertStoredValue(uri1, Settings.SHOULD_SYNC, "0") ;
    611         assertStoredValue(uri1, Settings.UNGROUPED_VISIBLE, "0") ;
    612         assertStoredValue(uri2, Settings.SHOULD_SYNC, "1") ;
    613         assertStoredValue(uri2, Settings.UNGROUPED_VISIBLE, "1") ;
    614     }
    615 
    616     public void testDisplayNameParsingWhenPartsUnspecified() {
    617         long rawContactId = createRawContact();
    618         ContentValues values = new ContentValues();
    619         values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr.");
    620         insertStructuredName(rawContactId, values);
    621 
    622         assertStructuredName(rawContactId, "Mr", "John", "Kevin", "von Smith", "Jr.");
    623     }
    624 
    625     public void testDisplayNameParsingWhenPartsAreNull() {
    626         long rawContactId = createRawContact();
    627         ContentValues values = new ContentValues();
    628         values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr.");
    629         values.putNull(StructuredName.GIVEN_NAME);
    630         values.putNull(StructuredName.FAMILY_NAME);
    631         insertStructuredName(rawContactId, values);
    632         assertStructuredName(rawContactId, "Mr", "John", "Kevin", "von Smith", "Jr.");
    633     }
    634 
    635     public void testDisplayNameParsingWhenPartsSpecified() {
    636         long rawContactId = createRawContact();
    637         ContentValues values = new ContentValues();
    638         values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr.");
    639         values.put(StructuredName.FAMILY_NAME, "Johnson");
    640         insertStructuredName(rawContactId, values);
    641 
    642         assertStructuredName(rawContactId, null, null, null, "Johnson", null);
    643     }
    644 
    645     public void testContactWithoutPhoneticName() {
    646         final long rawContactId = createRawContact(null);
    647 
    648         ContentValues values = new ContentValues();
    649         values.put(StructuredName.PREFIX, "Mr");
    650         values.put(StructuredName.GIVEN_NAME, "John");
    651         values.put(StructuredName.MIDDLE_NAME, "K.");
    652         values.put(StructuredName.FAMILY_NAME, "Doe");
    653         values.put(StructuredName.SUFFIX, "Jr.");
    654         Uri dataUri = insertStructuredName(rawContactId, values);
    655 
    656         values.clear();
    657         values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME);
    658         values.put(RawContacts.DISPLAY_NAME_PRIMARY, "John K. Doe, Jr.");
    659         values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "Doe, John K., Jr.");
    660         values.putNull(RawContacts.PHONETIC_NAME);
    661         values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED);
    662         values.put(RawContacts.SORT_KEY_PRIMARY, "John K. Doe, Jr.");
    663         values.put(RawContacts.SORT_KEY_ALTERNATIVE, "Doe, John K., Jr.");
    664 
    665         Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
    666         assertStoredValues(rawContactUri, values);
    667 
    668         values.clear();
    669         values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME);
    670         values.put(Contacts.DISPLAY_NAME_PRIMARY, "John K. Doe, Jr.");
    671         values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "Doe, John K., Jr.");
    672         values.putNull(Contacts.PHONETIC_NAME);
    673         values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED);
    674         values.put(Contacts.SORT_KEY_PRIMARY, "John K. Doe, Jr.");
    675         values.put(Contacts.SORT_KEY_ALTERNATIVE, "Doe, John K., Jr.");
    676 
    677         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
    678                 queryContactId(rawContactId));
    679         assertStoredValues(contactUri, values);
    680 
    681         // The same values should be available through a join with Data
    682         assertStoredValues(dataUri, values);
    683     }
    684 
    685     public void testContactWithChineseName() {
    686 
    687         // Only run this test when Chinese collation is supported
    688         if (!Arrays.asList(Collator.getAvailableLocales()).contains(Locale.CHINA)) {
    689             return;
    690         }
    691 
    692         long rawContactId = createRawContact(null);
    693 
    694         ContentValues values = new ContentValues();
    695         values.put(StructuredName.DISPLAY_NAME, "\u6BB5\u5C0F\u6D9B");
    696         Uri dataUri = insertStructuredName(rawContactId, values);
    697 
    698         values.clear();
    699         values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME);
    700         values.put(RawContacts.DISPLAY_NAME_PRIMARY, "\u6BB5\u5C0F\u6D9B");
    701         values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B");
    702         values.putNull(RawContacts.PHONETIC_NAME);
    703         values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED);
    704         values.put(RawContacts.SORT_KEY_PRIMARY, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B");
    705         values.put(RawContacts.SORT_KEY_ALTERNATIVE, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B");
    706 
    707         Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
    708         assertStoredValues(rawContactUri, values);
    709 
    710         values.clear();
    711         values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME);
    712         values.put(Contacts.DISPLAY_NAME_PRIMARY, "\u6BB5\u5C0F\u6D9B");
    713         values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B");
    714         values.putNull(Contacts.PHONETIC_NAME);
    715         values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED);
    716         values.put(Contacts.SORT_KEY_PRIMARY, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B");
    717         values.put(Contacts.SORT_KEY_ALTERNATIVE, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B");
    718 
    719         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
    720                 queryContactId(rawContactId));
    721         assertStoredValues(contactUri, values);
    722 
    723         // The same values should be available through a join with Data
    724         assertStoredValues(dataUri, values);
    725     }
    726 
    727     public void testContactWithJapaneseName() {
    728         long rawContactId = createRawContact(null);
    729 
    730         ContentValues values = new ContentValues();
    731         values.put(StructuredName.GIVEN_NAME, "\u7A7A\u6D77");
    732         values.put(StructuredName.PHONETIC_GIVEN_NAME, "\u304B\u3044\u304F\u3046");
    733         Uri dataUri = insertStructuredName(rawContactId, values);
    734 
    735         values.clear();
    736         values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME);
    737         values.put(RawContacts.DISPLAY_NAME_PRIMARY, "\u7A7A\u6D77");
    738         values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "\u7A7A\u6D77");
    739         values.put(RawContacts.PHONETIC_NAME, "\u304B\u3044\u304F\u3046");
    740         values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE);
    741         values.put(RawContacts.SORT_KEY_PRIMARY, "\u304B\u3044\u304F\u3046");
    742         values.put(RawContacts.SORT_KEY_ALTERNATIVE, "\u304B\u3044\u304F\u3046");
    743 
    744         Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
    745         assertStoredValues(rawContactUri, values);
    746 
    747         values.clear();
    748         values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME);
    749         values.put(Contacts.DISPLAY_NAME_PRIMARY, "\u7A7A\u6D77");
    750         values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "\u7A7A\u6D77");
    751         values.put(Contacts.PHONETIC_NAME, "\u304B\u3044\u304F\u3046");
    752         values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE);
    753         values.put(Contacts.SORT_KEY_PRIMARY, "\u304B\u3044\u304F\u3046");
    754         values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u304B\u3044\u304F\u3046");
    755 
    756         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
    757                 queryContactId(rawContactId));
    758         assertStoredValues(contactUri, values);
    759 
    760         // The same values should be available through a join with Data
    761         assertStoredValues(dataUri, values);
    762     }
    763 
    764     public void testDisplayNameUpdate() {
    765         long rawContactId1 = createRawContact();
    766         insertEmail(rawContactId1, "potato (at) acme.com", true);
    767 
    768         long rawContactId2 = createRawContact();
    769         insertPhoneNumber(rawContactId2, "123456789", true);
    770 
    771         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    772                 rawContactId1, rawContactId2);
    773 
    774         assertAggregated(rawContactId1, rawContactId2, "123456789");
    775 
    776         insertStructuredName(rawContactId2, "Potato", "Head");
    777 
    778         assertAggregated(rawContactId1, rawContactId2, "Potato Head");
    779         assertNetworkNotified(true);
    780     }
    781 
    782     public void testDisplayNameFromData() {
    783         long rawContactId = createRawContact();
    784         long contactId = queryContactId(rawContactId);
    785         ContentValues values = new ContentValues();
    786 
    787         Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
    788 
    789         assertStoredValue(uri, Contacts.DISPLAY_NAME, null);
    790         insertEmail(rawContactId, "mike (at) monstersinc.com");
    791         assertStoredValue(uri, Contacts.DISPLAY_NAME, "mike (at) monstersinc.com");
    792 
    793         insertEmail(rawContactId, "james (at) monstersinc.com", true);
    794         assertStoredValue(uri, Contacts.DISPLAY_NAME, "james (at) monstersinc.com");
    795 
    796         insertPhoneNumber(rawContactId, "1-800-466-4411");
    797         assertStoredValue(uri, Contacts.DISPLAY_NAME, "1-800-466-4411");
    798 
    799         // If there are title and company, the company is display name.
    800         values.clear();
    801         values.put(Organization.COMPANY, "Monsters Inc");
    802         Uri organizationUri = insertOrganization(rawContactId, values);
    803         assertStoredValue(uri, Contacts.DISPLAY_NAME, "Monsters Inc");
    804 
    805         // If there is nickname, that is display name.
    806         insertNickname(rawContactId, "Sully");
    807         assertStoredValue(uri, Contacts.DISPLAY_NAME, "Sully");
    808 
    809         // If there is structured name, that is display name.
    810         values.clear();
    811         values.put(StructuredName.GIVEN_NAME, "James");
    812         values.put(StructuredName.MIDDLE_NAME, "P.");
    813         values.put(StructuredName.FAMILY_NAME, "Sullivan");
    814         insertStructuredName(rawContactId, values);
    815         assertStoredValue(uri, Contacts.DISPLAY_NAME, "James P. Sullivan");
    816     }
    817 
    818     public void testDisplayNameFromOrganizationWithoutPhoneticName() {
    819         long rawContactId = createRawContact();
    820         long contactId = queryContactId(rawContactId);
    821         ContentValues values = new ContentValues();
    822 
    823         Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
    824 
    825         // If there is title without company, the title is display name.
    826         values.clear();
    827         values.put(Organization.TITLE, "Protagonist");
    828         Uri organizationUri = insertOrganization(rawContactId, values);
    829         assertStoredValue(uri, Contacts.DISPLAY_NAME, "Protagonist");
    830 
    831         // If there are title and company, the company is display name.
    832         values.clear();
    833         values.put(Organization.COMPANY, "Monsters Inc");
    834         mResolver.update(organizationUri, values, null, null);
    835 
    836         values.clear();
    837         values.put(Contacts.DISPLAY_NAME, "Monsters Inc");
    838         values.putNull(Contacts.PHONETIC_NAME);
    839         values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED);
    840         values.put(Contacts.SORT_KEY_PRIMARY, "Monsters Inc");
    841         values.put(Contacts.SORT_KEY_ALTERNATIVE, "Monsters Inc");
    842         assertStoredValues(uri, values);
    843     }
    844 
    845     public void testDisplayNameFromOrganizationWithJapanesePhoneticName() {
    846         long rawContactId = createRawContact();
    847         long contactId = queryContactId(rawContactId);
    848         ContentValues values = new ContentValues();
    849 
    850         Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
    851 
    852         // If there is title without company, the title is display name.
    853         values.clear();
    854         values.put(Organization.COMPANY, "DoCoMo");
    855         values.put(Organization.PHONETIC_NAME, "\u30C9\u30B3\u30E2");
    856         Uri organizationUri = insertOrganization(rawContactId, values);
    857 
    858         values.clear();
    859         values.put(Contacts.DISPLAY_NAME, "DoCoMo");
    860         values.put(Contacts.PHONETIC_NAME, "\u30C9\u30B3\u30E2");
    861         values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE);
    862         values.put(Contacts.SORT_KEY_PRIMARY, "\u30C9\u30B3\u30E2");
    863         values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u30C9\u30B3\u30E2");
    864         assertStoredValues(uri, values);
    865     }
    866 
    867     public void testDisplayNameFromOrganizationWithChineseName() {
    868         boolean hasChineseCollator = false;
    869         final Locale locale[] = Collator.getAvailableLocales();
    870         for (int i = 0; i < locale.length; i++) {
    871             if (locale[i].equals(Locale.CHINA)) {
    872                 hasChineseCollator = true;
    873                 break;
    874             }
    875         }
    876 
    877         if (!hasChineseCollator) {
    878             return;
    879         }
    880 
    881         long rawContactId = createRawContact();
    882         long contactId = queryContactId(rawContactId);
    883         ContentValues values = new ContentValues();
    884 
    885         Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
    886 
    887         // If there is title without company, the title is display name.
    888         values.clear();
    889         values.put(Organization.COMPANY, "\u4E2D\u56FD\u7535\u4FE1");
    890         Uri organizationUri = insertOrganization(rawContactId, values);
    891 
    892         values.clear();
    893         values.put(Contacts.DISPLAY_NAME, "\u4E2D\u56FD\u7535\u4FE1");
    894         values.putNull(Contacts.PHONETIC_NAME);
    895         values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED);
    896         values.put(Contacts.SORT_KEY_PRIMARY, "ZHONG \u4E2D GUO \u56FD DIAN \u7535 XIN \u4FE1");
    897         values.put(Contacts.SORT_KEY_ALTERNATIVE, "ZHONG \u4E2D GUO \u56FD DIAN \u7535 XIN \u4FE1");
    898         assertStoredValues(uri, values);
    899     }
    900 
    901     public void testLookupByOrganization() {
    902         long rawContactId = createRawContact();
    903         long contactId = queryContactId(rawContactId);
    904         ContentValues values = new ContentValues();
    905 
    906         values.clear();
    907         values.put(Organization.COMPANY, "acmecorp");
    908         values.put(Organization.TITLE, "president");
    909         Uri organizationUri = insertOrganization(rawContactId, values);
    910 
    911         assertContactFilter(contactId, "acmecorp");
    912         assertContactFilter(contactId, "president");
    913 
    914         values.clear();
    915         values.put(Organization.DEPARTMENT, "software");
    916         mResolver.update(organizationUri, values, null, null);
    917 
    918         assertContactFilter(contactId, "acmecorp");
    919         assertContactFilter(contactId, "president");
    920 
    921         values.clear();
    922         values.put(Organization.COMPANY, "incredibles");
    923         mResolver.update(organizationUri, values, null, null);
    924 
    925         assertContactFilter(contactId, "incredibles");
    926         assertContactFilter(contactId, "president");
    927 
    928         values.clear();
    929         values.put(Organization.TITLE, "director");
    930         mResolver.update(organizationUri, values, null, null);
    931 
    932         assertContactFilter(contactId, "incredibles");
    933         assertContactFilter(contactId, "director");
    934 
    935         values.clear();
    936         values.put(Organization.COMPANY, "monsters");
    937         values.put(Organization.TITLE, "scarer");
    938         mResolver.update(organizationUri, values, null, null);
    939 
    940         assertContactFilter(contactId, "monsters");
    941         assertContactFilter(contactId, "scarer");
    942     }
    943 
    944     private void assertContactFilter(long contactId, String filter) {
    945         Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(filter));
    946         assertStoredValue(filterUri, Contacts._ID, contactId);
    947     }
    948 
    949     public void testSearchSnippetOrganization() throws Exception {
    950         long rawContactId = createRawContactWithName();
    951         long contactId = queryContactId(rawContactId);
    952 
    953         // Some random data element
    954         insertEmail(rawContactId, "inc (at) corp.com");
    955 
    956         ContentValues values = new ContentValues();
    957         values.clear();
    958         values.put(Organization.COMPANY, "acmecorp");
    959         values.put(Organization.TITLE, "engineer");
    960         Uri organizationUri = insertOrganization(rawContactId, values);
    961 
    962         // Add another matching organization
    963         values.put(Organization.COMPANY, "acmeinc");
    964         insertOrganization(rawContactId, values);
    965 
    966         // Add another non-matching organization
    967         values.put(Organization.COMPANY, "corpacme");
    968         insertOrganization(rawContactId, values);
    969 
    970         // And another data element
    971         insertEmail(rawContactId, "emca (at) corp.com", true, Email.TYPE_CUSTOM, "Custom");
    972 
    973         Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode("acme"));
    974 
    975         values.clear();
    976         values.put(Contacts._ID, contactId);
    977         values.put(SearchSnippetColumns.SNIPPET_DATA_ID, ContentUris.parseId(organizationUri));
    978         values.put(SearchSnippetColumns.SNIPPET_DATA1, "acmecorp");
    979         values.put(SearchSnippetColumns.SNIPPET_DATA4, "engineer");
    980         values.put(SearchSnippetColumns.SNIPPET_MIMETYPE, Organization.CONTENT_ITEM_TYPE);
    981         assertStoredValues(filterUri, values);
    982     }
    983 
    984     public void testSearchSnippetEmail() throws Exception {
    985         long rawContactId = createRawContact();
    986         long contactId = queryContactId(rawContactId);
    987         ContentValues values = new ContentValues();
    988 
    989         Uri dataUri = insertEmail(rawContactId, "acme (at) corp.com", true, Email.TYPE_CUSTOM, "Custom");
    990 
    991         Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode("acme"));
    992 
    993         values.clear();
    994         values.put(Contacts._ID, contactId);
    995         values.put(SearchSnippetColumns.SNIPPET_DATA1, "acme (at) corp.com");
    996         values.put(SearchSnippetColumns.SNIPPET_DATA_ID, ContentUris.parseId(dataUri));
    997         values.put(SearchSnippetColumns.SNIPPET_MIMETYPE, Email.CONTENT_ITEM_TYPE);
    998         values.put(SearchSnippetColumns.SNIPPET_DATA2, Email.TYPE_CUSTOM);
    999         values.put(SearchSnippetColumns.SNIPPET_DATA3, "Custom");
   1000         assertStoredValues(filterUri, values);
   1001     }
   1002 
   1003     public void testSearchSnippetNickname() throws Exception {
   1004         long rawContactId = createRawContactWithName();
   1005         long contactId = queryContactId(rawContactId);
   1006         ContentValues values = new ContentValues();
   1007 
   1008         Uri dataUri = insertNickname(rawContactId, "Incredible");
   1009 
   1010         Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode("inc"));
   1011 
   1012         values.clear();
   1013         values.put(Contacts._ID, contactId);
   1014         values.put(SearchSnippetColumns.SNIPPET_DATA1, "Incredible");
   1015         values.put(SearchSnippetColumns.SNIPPET_DATA_ID, ContentUris.parseId(dataUri));
   1016         values.put(SearchSnippetColumns.SNIPPET_MIMETYPE, Nickname.CONTENT_ITEM_TYPE);
   1017         assertStoredValues(filterUri, values);
   1018     }
   1019 
   1020     public void testDisplayNameUpdateFromStructuredNameUpdate() {
   1021         long rawContactId = createRawContact();
   1022         Uri nameUri = insertStructuredName(rawContactId, "Slinky", "Dog");
   1023 
   1024         long contactId = queryContactId(rawContactId);
   1025 
   1026         Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1027         assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky Dog");
   1028 
   1029         ContentValues values = new ContentValues();
   1030         values.putNull(StructuredName.FAMILY_NAME);
   1031 
   1032         mResolver.update(nameUri, values, null, null);
   1033         assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky");
   1034 
   1035         values.putNull(StructuredName.GIVEN_NAME);
   1036 
   1037         mResolver.update(nameUri, values, null, null);
   1038         assertStoredValue(uri, Contacts.DISPLAY_NAME, null);
   1039 
   1040         values.put(StructuredName.FAMILY_NAME, "Dog");
   1041         mResolver.update(nameUri, values, null, null);
   1042 
   1043         assertStoredValue(uri, Contacts.DISPLAY_NAME, "Dog");
   1044     }
   1045 
   1046     public void testInsertDataWithContentProviderOperations() throws Exception {
   1047         ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
   1048                 .withValues(new ContentValues())
   1049                 .build();
   1050         ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
   1051                 .withValueBackReference(Data.RAW_CONTACT_ID, 0)
   1052                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
   1053                 .withValue(StructuredName.GIVEN_NAME, "John")
   1054                 .withValue(StructuredName.FAMILY_NAME, "Doe")
   1055                 .build();
   1056         ContentProviderResult[] results =
   1057                 mResolver.applyBatch(ContactsContract.AUTHORITY, Lists.newArrayList(cpo1, cpo2));
   1058         long contactId = queryContactId(ContentUris.parseId(results[0].uri));
   1059         Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1060         assertStoredValue(uri, Contacts.DISPLAY_NAME, "John Doe");
   1061     }
   1062 
   1063     public void testSendToVoicemailDefault() {
   1064         long rawContactId = createRawContactWithName();
   1065         long contactId = queryContactId(rawContactId);
   1066 
   1067         Cursor c = queryContact(contactId);
   1068         assertTrue(c.moveToNext());
   1069         int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL));
   1070         assertEquals(0, sendToVoicemail);
   1071         c.close();
   1072     }
   1073 
   1074     public void testSetSendToVoicemailAndRingtone() {
   1075         long rawContactId = createRawContactWithName();
   1076         long contactId = queryContactId(rawContactId);
   1077 
   1078         updateSendToVoicemailAndRingtone(contactId, true, "foo");
   1079         assertSendToVoicemailAndRingtone(contactId, true, "foo");
   1080         assertNetworkNotified(false);
   1081 
   1082         updateSendToVoicemailAndRingtoneWithSelection(contactId, false, "bar");
   1083         assertSendToVoicemailAndRingtone(contactId, false, "bar");
   1084         assertNetworkNotified(false);
   1085     }
   1086 
   1087     public void testSendToVoicemailAndRingtoneAfterAggregation() {
   1088         long rawContactId1 = createRawContactWithName("a", "b");
   1089         long contactId1 = queryContactId(rawContactId1);
   1090         updateSendToVoicemailAndRingtone(contactId1, true, "foo");
   1091 
   1092         long rawContactId2 = createRawContactWithName("c", "d");
   1093         long contactId2 = queryContactId(rawContactId2);
   1094         updateSendToVoicemailAndRingtone(contactId2, true, "bar");
   1095 
   1096         // Aggregate them
   1097         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1098                 rawContactId1, rawContactId2);
   1099 
   1100         // Both contacts had "send to VM", the contact now has the same value
   1101         assertSendToVoicemailAndRingtone(contactId1, true, "foo,bar"); // Either foo or bar
   1102     }
   1103 
   1104     public void testDoNotSendToVoicemailAfterAggregation() {
   1105         long rawContactId1 = createRawContactWithName("e", "f");
   1106         long contactId1 = queryContactId(rawContactId1);
   1107         updateSendToVoicemailAndRingtone(contactId1, true, null);
   1108 
   1109         long rawContactId2 = createRawContactWithName("g", "h");
   1110         long contactId2 = queryContactId(rawContactId2);
   1111         updateSendToVoicemailAndRingtone(contactId2, false, null);
   1112 
   1113         // Aggregate them
   1114         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1115                 rawContactId1, rawContactId2);
   1116 
   1117         // Since one of the contacts had "don't send to VM" that setting wins for the aggregate
   1118         assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), false, null);
   1119     }
   1120 
   1121     public void testSetSendToVoicemailAndRingtonePreservedAfterJoinAndSplit() {
   1122         long rawContactId1 = createRawContactWithName("i", "j");
   1123         long contactId1 = queryContactId(rawContactId1);
   1124         updateSendToVoicemailAndRingtone(contactId1, true, "foo");
   1125 
   1126         long rawContactId2 = createRawContactWithName("k", "l");
   1127         long contactId2 = queryContactId(rawContactId2);
   1128         updateSendToVoicemailAndRingtone(contactId2, false, "bar");
   1129 
   1130         // Aggregate them
   1131         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1132                 rawContactId1, rawContactId2);
   1133 
   1134         // Split them
   1135         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
   1136                 rawContactId1, rawContactId2);
   1137 
   1138         assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), true, "foo");
   1139         assertSendToVoicemailAndRingtone(queryContactId(rawContactId2), false, "bar");
   1140     }
   1141 
   1142     public void testStatusUpdateInsert() {
   1143         long rawContactId = createRawContact();
   1144         Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
   1145         long dataId = ContentUris.parseId(imUri);
   1146 
   1147         ContentValues values = new ContentValues();
   1148         values.put(StatusUpdates.DATA_ID, dataId);
   1149         values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM);
   1150         values.putNull(StatusUpdates.CUSTOM_PROTOCOL);
   1151         values.put(StatusUpdates.IM_HANDLE, "aim");
   1152         values.put(StatusUpdates.PRESENCE, StatusUpdates.INVISIBLE);
   1153         values.put(StatusUpdates.STATUS, "Hiding");
   1154         values.put(StatusUpdates.STATUS_TIMESTAMP, 100);
   1155         values.put(StatusUpdates.STATUS_RES_PACKAGE, "a.b.c");
   1156         values.put(StatusUpdates.STATUS_ICON, 1234);
   1157         values.put(StatusUpdates.STATUS_LABEL, 2345);
   1158 
   1159         Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values);
   1160 
   1161         assertStoredValues(resultUri, values);
   1162 
   1163         long contactId = queryContactId(rawContactId);
   1164         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1165 
   1166         values.clear();
   1167         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
   1168         values.put(Contacts.CONTACT_STATUS, "Hiding");
   1169         values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100);
   1170         values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "a.b.c");
   1171         values.put(Contacts.CONTACT_STATUS_ICON, 1234);
   1172         values.put(Contacts.CONTACT_STATUS_LABEL, 2345);
   1173 
   1174         assertStoredValues(contactUri, values);
   1175 
   1176         values.clear();
   1177         values.put(StatusUpdates.DATA_ID, dataId);
   1178         values.put(StatusUpdates.STATUS, "Cloaked");
   1179         values.put(StatusUpdates.STATUS_TIMESTAMP, 200);
   1180         values.put(StatusUpdates.STATUS_RES_PACKAGE, "d.e.f");
   1181         values.put(StatusUpdates.STATUS_ICON, 4321);
   1182         values.put(StatusUpdates.STATUS_LABEL, 5432);
   1183         mResolver.insert(StatusUpdates.CONTENT_URI, values);
   1184 
   1185         values.clear();
   1186         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
   1187         values.put(Contacts.CONTACT_STATUS, "Cloaked");
   1188         values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 200);
   1189         values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "d.e.f");
   1190         values.put(Contacts.CONTACT_STATUS_ICON, 4321);
   1191         values.put(Contacts.CONTACT_STATUS_LABEL, 5432);
   1192         assertStoredValues(contactUri, values);
   1193     }
   1194 
   1195     public void testStatusUpdateInferAttribution() {
   1196         long rawContactId = createRawContact();
   1197         Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
   1198         long dataId = ContentUris.parseId(imUri);
   1199 
   1200         ContentValues values = new ContentValues();
   1201         values.put(StatusUpdates.DATA_ID, dataId);
   1202         values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM);
   1203         values.put(StatusUpdates.IM_HANDLE, "aim");
   1204         values.put(StatusUpdates.STATUS, "Hiding");
   1205 
   1206         Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values);
   1207 
   1208         values.clear();
   1209         values.put(StatusUpdates.DATA_ID, dataId);
   1210         values.put(StatusUpdates.STATUS_LABEL, com.android.internal.R.string.imProtocolAim);
   1211         values.put(StatusUpdates.STATUS, "Hiding");
   1212 
   1213         assertStoredValues(resultUri, values);
   1214     }
   1215 
   1216     public void testStatusUpdateMatchingImOrEmail() {
   1217         long rawContactId = createRawContact();
   1218         insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
   1219         insertImHandle(rawContactId, Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im");
   1220         insertEmail(rawContactId, "m (at) acme.com");
   1221 
   1222         // Match on IM (standard)
   1223         insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available");
   1224 
   1225         // Match on IM (custom)
   1226         insertStatusUpdate(Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im", StatusUpdates.IDLE, "Idle");
   1227 
   1228         // Match on Email
   1229         insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "m (at) acme.com", StatusUpdates.AWAY, "Away");
   1230 
   1231         // No match
   1232         insertStatusUpdate(Im.PROTOCOL_ICQ, null, "12345", StatusUpdates.DO_NOT_DISTURB, "Go away");
   1233 
   1234         Cursor c = mResolver.query(StatusUpdates.CONTENT_URI, new String[] {
   1235                 StatusUpdates.DATA_ID, StatusUpdates.PROTOCOL, StatusUpdates.CUSTOM_PROTOCOL,
   1236                 StatusUpdates.PRESENCE, StatusUpdates.STATUS},
   1237                 PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null, StatusUpdates.DATA_ID);
   1238         assertTrue(c.moveToNext());
   1239         assertStatusUpdate(c, Im.PROTOCOL_AIM, null, StatusUpdates.AVAILABLE, "Available");
   1240         assertTrue(c.moveToNext());
   1241         assertStatusUpdate(c, Im.PROTOCOL_CUSTOM, "my_im_proto", StatusUpdates.IDLE, "Idle");
   1242         assertTrue(c.moveToNext());
   1243         assertStatusUpdate(c, Im.PROTOCOL_GOOGLE_TALK, null, StatusUpdates.AWAY, "Away");
   1244         assertFalse(c.moveToNext());
   1245         c.close();
   1246 
   1247         long contactId = queryContactId(rawContactId);
   1248         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1249 
   1250         ContentValues values = new ContentValues();
   1251         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE);
   1252         values.put(Contacts.CONTACT_STATUS, "Available");
   1253         assertStoredValuesWithProjection(contactUri, values);
   1254     }
   1255 
   1256     public void testStatusUpdateUpdateAndDelete() {
   1257         long rawContactId = createRawContact();
   1258         insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
   1259 
   1260         long contactId = queryContactId(rawContactId);
   1261         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1262 
   1263         ContentValues values = new ContentValues();
   1264         values.putNull(Contacts.CONTACT_PRESENCE);
   1265         values.putNull(Contacts.CONTACT_STATUS);
   1266         assertStoredValuesWithProjection(contactUri, values);
   1267 
   1268         insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AWAY, "BUSY");
   1269         insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.DO_NOT_DISTURB, "GO AWAY");
   1270         Uri statusUri =
   1271             insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available");
   1272         long statusId = ContentUris.parseId(statusUri);
   1273 
   1274         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE);
   1275         values.put(Contacts.CONTACT_STATUS, "Available");
   1276         assertStoredValuesWithProjection(contactUri, values);
   1277 
   1278         // update status_updates table to set new values for
   1279         //     status_updates.status
   1280         //     status_updates.status_ts
   1281         //     presence
   1282         long updatedTs = 200;
   1283         String testUpdate = "test_update";
   1284         String selection = StatusUpdates.DATA_ID + "=" + statusId;
   1285         values.clear();
   1286         values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs);
   1287         values.put(StatusUpdates.STATUS, testUpdate);
   1288         values.put(StatusUpdates.PRESENCE, "presence_test");
   1289         mResolver.update(StatusUpdates.CONTENT_URI, values,
   1290                 StatusUpdates.DATA_ID + "=" + statusId, null);
   1291         assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values);
   1292 
   1293         // update status_updates table to set new values for columns in status_updates table ONLY
   1294         // i.e., no rows in presence table are to be updated.
   1295         updatedTs = 300;
   1296         testUpdate = "test_update_new";
   1297         selection = StatusUpdates.DATA_ID + "=" + statusId;
   1298         values.clear();
   1299         values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs);
   1300         values.put(StatusUpdates.STATUS, testUpdate);
   1301         mResolver.update(StatusUpdates.CONTENT_URI, values,
   1302                 StatusUpdates.DATA_ID + "=" + statusId, null);
   1303         // make sure the presence column value is still the old value
   1304         values.put(StatusUpdates.PRESENCE, "presence_test");
   1305         assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values);
   1306 
   1307         // update status_updates table to set new values for columns in presence table ONLY
   1308         // i.e., no rows in status_updates table are to be updated.
   1309         selection = StatusUpdates.DATA_ID + "=" + statusId;
   1310         values.clear();
   1311         values.put(StatusUpdates.PRESENCE, "presence_test_new");
   1312         mResolver.update(StatusUpdates.CONTENT_URI, values,
   1313                 StatusUpdates.DATA_ID + "=" + statusId, null);
   1314         // make sure the status_updates table is not updated
   1315         values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs);
   1316         values.put(StatusUpdates.STATUS, testUpdate);
   1317         assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values);
   1318 
   1319         // effect "delete status_updates" operation and expect the following
   1320         //   data deleted from status_updates table
   1321         //   presence set to null
   1322         mResolver.delete(StatusUpdates.CONTENT_URI, StatusUpdates.DATA_ID + "=" + statusId, null);
   1323         values.clear();
   1324         values.putNull(Contacts.CONTACT_PRESENCE);
   1325         assertStoredValuesWithProjection(contactUri, values);
   1326     }
   1327 
   1328     public void testStatusUpdateWithTimestamp() {
   1329         long rawContactId = createRawContact();
   1330         insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
   1331         insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk");
   1332 
   1333         long contactId = queryContactId(rawContactId);
   1334         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1335         insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Offline", 80);
   1336         insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Available", 100);
   1337         insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", 0, "Busy", 90);
   1338 
   1339         // Should return the latest status
   1340         ContentValues values = new ContentValues();
   1341         values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100);
   1342         values.put(Contacts.CONTACT_STATUS, "Available");
   1343         assertStoredValuesWithProjection(contactUri, values);
   1344     }
   1345 
   1346     private void assertStatusUpdate(Cursor c, int protocol, String customProtocol, int presence,
   1347             String status) {
   1348         ContentValues values = new ContentValues();
   1349         values.put(StatusUpdates.PROTOCOL, protocol);
   1350         values.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol);
   1351         values.put(StatusUpdates.PRESENCE_STATUS, presence);
   1352         values.put(StatusUpdates.STATUS, status);
   1353         assertCursorValues(c, values);
   1354     }
   1355 
   1356     public void testSingleStatusUpdateRowPerContact() {
   1357         int protocol1 = Im.PROTOCOL_GOOGLE_TALK;
   1358         String handle1 = "test (at) gmail.com";
   1359 
   1360         long rawContactId1 = createRawContact();
   1361         insertImHandle(rawContactId1, protocol1, null, handle1);
   1362 
   1363         insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AVAILABLE, "Green");
   1364         insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AWAY, "Yellow");
   1365         insertStatusUpdate(protocol1, null, handle1, StatusUpdates.INVISIBLE, "Red");
   1366 
   1367         Cursor c = queryContact(queryContactId(rawContactId1),
   1368                 new String[] {Contacts.CONTACT_PRESENCE, Contacts.CONTACT_STATUS});
   1369         assertEquals(1, c.getCount());
   1370 
   1371         c.moveToFirst();
   1372         assertEquals(StatusUpdates.INVISIBLE, c.getInt(0));
   1373         assertEquals("Red", c.getString(1));
   1374         c.close();
   1375     }
   1376 
   1377     private void updateSendToVoicemailAndRingtone(long contactId, boolean sendToVoicemail,
   1378             String ringtone) {
   1379         ContentValues values = new ContentValues();
   1380         values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail);
   1381         if (ringtone != null) {
   1382             values.put(Contacts.CUSTOM_RINGTONE, ringtone);
   1383         }
   1384 
   1385         final Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1386         int count = mResolver.update(uri, values, null, null);
   1387         assertEquals(1, count);
   1388     }
   1389 
   1390     private void updateSendToVoicemailAndRingtoneWithSelection(long contactId,
   1391             boolean sendToVoicemail, String ringtone) {
   1392         ContentValues values = new ContentValues();
   1393         values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail);
   1394         if (ringtone != null) {
   1395             values.put(Contacts.CUSTOM_RINGTONE, ringtone);
   1396         }
   1397 
   1398         int count = mResolver.update(Contacts.CONTENT_URI, values, Contacts._ID + "=" + contactId,
   1399                 null);
   1400         assertEquals(1, count);
   1401     }
   1402 
   1403     private void assertSendToVoicemailAndRingtone(long contactId, boolean expectedSendToVoicemail,
   1404             String expectedRingtone) {
   1405         Cursor c = queryContact(contactId);
   1406         assertTrue(c.moveToNext());
   1407         int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL));
   1408         assertEquals(expectedSendToVoicemail ? 1 : 0, sendToVoicemail);
   1409         String ringtone = c.getString(c.getColumnIndex(Contacts.CUSTOM_RINGTONE));
   1410         if (expectedRingtone == null) {
   1411             assertNull(ringtone);
   1412         } else {
   1413             assertTrue(ArrayUtils.contains(expectedRingtone.split(","), ringtone));
   1414         }
   1415         c.close();
   1416     }
   1417 
   1418     public void testGroupCreationAfterMembershipInsert() {
   1419         long rawContactId1 = createRawContact(mAccount);
   1420         Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1");
   1421 
   1422         long groupId = assertSingleGroup(NO_LONG, mAccount, "gsid1", null);
   1423         assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri),
   1424                 rawContactId1, groupId, "gsid1");
   1425     }
   1426 
   1427     public void testGroupReuseAfterMembershipInsert() {
   1428         long rawContactId1 = createRawContact(mAccount);
   1429         long groupId1 = createGroup(mAccount, "gsid1", "title1");
   1430         Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1");
   1431 
   1432         assertSingleGroup(groupId1, mAccount, "gsid1", "title1");
   1433         assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri),
   1434                 rawContactId1, groupId1, "gsid1");
   1435     }
   1436 
   1437     public void testGroupInsertFailureOnGroupIdConflict() {
   1438         long rawContactId1 = createRawContact(mAccount);
   1439         long groupId1 = createGroup(mAccount, "gsid1", "title1");
   1440 
   1441         ContentValues values = new ContentValues();
   1442         values.put(GroupMembership.RAW_CONTACT_ID, rawContactId1);
   1443         values.put(GroupMembership.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
   1444         values.put(GroupMembership.GROUP_SOURCE_ID, "gsid1");
   1445         values.put(GroupMembership.GROUP_ROW_ID, groupId1);
   1446         try {
   1447             mResolver.insert(Data.CONTENT_URI, values);
   1448             fail("the insert was expected to fail, but it succeeded");
   1449         } catch (IllegalArgumentException e) {
   1450             // this was expected
   1451         }
   1452     }
   1453 
   1454     public void testContactVisibilityUpdateOnMembershipChange() {
   1455         long rawContactId = createRawContact(mAccount);
   1456         assertVisibility(rawContactId, "0");
   1457 
   1458         long visibleGroupId = createGroup(mAccount, "123", "Visible", 1);
   1459         long invisibleGroupId = createGroup(mAccount, "567", "Invisible", 0);
   1460 
   1461         Uri membership1 = insertGroupMembership(rawContactId, visibleGroupId);
   1462         assertVisibility(rawContactId, "1");
   1463 
   1464         Uri membership2 = insertGroupMembership(rawContactId, invisibleGroupId);
   1465         assertVisibility(rawContactId, "1");
   1466 
   1467         mResolver.delete(membership1, null, null);
   1468         assertVisibility(rawContactId, "0");
   1469 
   1470         ContentValues values = new ContentValues();
   1471         values.put(GroupMembership.GROUP_ROW_ID, visibleGroupId);
   1472 
   1473         mResolver.update(membership2, values, null, null);
   1474         assertVisibility(rawContactId, "1");
   1475     }
   1476 
   1477     private void assertVisibility(long rawContactId, String expectedValue) {
   1478         assertStoredValue(Contacts.CONTENT_URI, Contacts._ID + "=" + queryContactId(rawContactId),
   1479                 null, Contacts.IN_VISIBLE_GROUP, expectedValue);
   1480     }
   1481 
   1482     public void testContentEntityIterator() throws RemoteException {
   1483         // create multiple contacts and check that the selected ones are returned
   1484         long id;
   1485 
   1486         long groupId1 = createGroup(mAccount, "gsid1", "title1");
   1487         long groupId2 = createGroup(mAccount, "gsid2", "title2");
   1488 
   1489         id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c0");
   1490         insertGroupMembership(id, "gsid1");
   1491         insertEmail(id, "c0 (at) email.com");
   1492         insertPhoneNumber(id, "5551212c0");
   1493 
   1494         long c1 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c1");
   1495         Uri id_1_0 = insertGroupMembership(id, "gsid1");
   1496         Uri id_1_1 = insertGroupMembership(id, "gsid2");
   1497         Uri id_1_2 = insertEmail(id, "c1 (at) email.com");
   1498         Uri id_1_3 = insertPhoneNumber(id, "5551212c1");
   1499 
   1500         long c2 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c2");
   1501         Uri id_2_0 = insertGroupMembership(id, "gsid1");
   1502         Uri id_2_1 = insertEmail(id, "c2 (at) email.com");
   1503         Uri id_2_2 = insertPhoneNumber(id, "5551212c2");
   1504 
   1505         long c3 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c3");
   1506         Uri id_3_0 = insertGroupMembership(id, groupId2);
   1507         Uri id_3_1 = insertEmail(id, "c3 (at) email.com");
   1508         Uri id_3_2 = insertPhoneNumber(id, "5551212c3");
   1509 
   1510         EntityIterator iterator = RawContacts.newEntityIterator(mResolver.query(
   1511                 maybeAddAccountQueryParameters(RawContactsEntity.CONTENT_URI, mAccount), null,
   1512                 RawContacts.SOURCE_ID + " in ('c1', 'c2', 'c3')", null, null));
   1513         Entity entity;
   1514         ContentValues[] subValues;
   1515         entity = iterator.next();
   1516         assertEquals(c1, (long) entity.getEntityValues().getAsLong(RawContacts._ID));
   1517         subValues = asSortedContentValuesArray(entity.getSubValues());
   1518         assertEquals(4, subValues.length);
   1519         assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE,
   1520                 Data._ID, id_1_0,
   1521                 GroupMembership.GROUP_ROW_ID, groupId1,
   1522                 GroupMembership.GROUP_SOURCE_ID, "gsid1");
   1523         assertDataRow(subValues[1], GroupMembership.CONTENT_ITEM_TYPE,
   1524                 Data._ID, id_1_1,
   1525                 GroupMembership.GROUP_ROW_ID, groupId2,
   1526                 GroupMembership.GROUP_SOURCE_ID, "gsid2");
   1527         assertDataRow(subValues[2], Email.CONTENT_ITEM_TYPE,
   1528                 Data._ID, id_1_2,
   1529                 Email.DATA, "c1 (at) email.com");
   1530         assertDataRow(subValues[3], Phone.CONTENT_ITEM_TYPE,
   1531                 Data._ID, id_1_3,
   1532                 Email.DATA, "5551212c1");
   1533 
   1534         entity = iterator.next();
   1535         assertEquals(c2, (long) entity.getEntityValues().getAsLong(RawContacts._ID));
   1536         subValues = asSortedContentValuesArray(entity.getSubValues());
   1537         assertEquals(3, subValues.length);
   1538         assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE,
   1539                 Data._ID, id_2_0,
   1540                 GroupMembership.GROUP_ROW_ID, groupId1,
   1541                 GroupMembership.GROUP_SOURCE_ID, "gsid1");
   1542         assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE,
   1543                 Data._ID, id_2_1,
   1544                 Email.DATA, "c2 (at) email.com");
   1545         assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE,
   1546                 Data._ID, id_2_2,
   1547                 Email.DATA, "5551212c2");
   1548 
   1549         entity = iterator.next();
   1550         assertEquals(c3, (long) entity.getEntityValues().getAsLong(RawContacts._ID));
   1551         subValues = asSortedContentValuesArray(entity.getSubValues());
   1552         assertEquals(3, subValues.length);
   1553         assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE,
   1554                 Data._ID, id_3_0,
   1555                 GroupMembership.GROUP_ROW_ID, groupId2,
   1556                 GroupMembership.GROUP_SOURCE_ID, "gsid2");
   1557         assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE,
   1558                 Data._ID, id_3_1,
   1559                 Email.DATA, "c3 (at) email.com");
   1560         assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE,
   1561                 Data._ID, id_3_2,
   1562                 Email.DATA, "5551212c3");
   1563 
   1564         assertFalse(iterator.hasNext());
   1565         iterator.close();
   1566     }
   1567 
   1568     public void testDataCreateUpdateDeleteByMimeType() throws Exception {
   1569         long rawContactId = createRawContact();
   1570 
   1571         ContentValues values = new ContentValues();
   1572         values.put(Data.RAW_CONTACT_ID, rawContactId);
   1573         values.put(Data.MIMETYPE, "testmimetype");
   1574         values.put(Data.RES_PACKAGE, "oldpackage");
   1575         values.put(Data.IS_PRIMARY, 1);
   1576         values.put(Data.IS_SUPER_PRIMARY, 1);
   1577         values.put(Data.DATA1, "old1");
   1578         values.put(Data.DATA2, "old2");
   1579         values.put(Data.DATA3, "old3");
   1580         values.put(Data.DATA4, "old4");
   1581         values.put(Data.DATA5, "old5");
   1582         values.put(Data.DATA6, "old6");
   1583         values.put(Data.DATA7, "old7");
   1584         values.put(Data.DATA8, "old8");
   1585         values.put(Data.DATA9, "old9");
   1586         values.put(Data.DATA10, "old10");
   1587         values.put(Data.DATA11, "old11");
   1588         values.put(Data.DATA12, "old12");
   1589         values.put(Data.DATA13, "old13");
   1590         values.put(Data.DATA14, "old14");
   1591         values.put(Data.DATA15, "old15");
   1592         Uri uri = mResolver.insert(Data.CONTENT_URI, values);
   1593         assertStoredValues(uri, values);
   1594         assertNetworkNotified(true);
   1595 
   1596         values.clear();
   1597         values.put(Data.RES_PACKAGE, "newpackage");
   1598         values.put(Data.IS_PRIMARY, 0);
   1599         values.put(Data.IS_SUPER_PRIMARY, 0);
   1600         values.put(Data.DATA1, "new1");
   1601         values.put(Data.DATA2, "new2");
   1602         values.put(Data.DATA3, "new3");
   1603         values.put(Data.DATA4, "new4");
   1604         values.put(Data.DATA5, "new5");
   1605         values.put(Data.DATA6, "new6");
   1606         values.put(Data.DATA7, "new7");
   1607         values.put(Data.DATA8, "new8");
   1608         values.put(Data.DATA9, "new9");
   1609         values.put(Data.DATA10, "new10");
   1610         values.put(Data.DATA11, "new11");
   1611         values.put(Data.DATA12, "new12");
   1612         values.put(Data.DATA13, "new13");
   1613         values.put(Data.DATA14, "new14");
   1614         values.put(Data.DATA15, "new15");
   1615         mResolver.update(Data.CONTENT_URI, values, Data.RAW_CONTACT_ID + "=" + rawContactId +
   1616                 " AND " + Data.MIMETYPE + "='testmimetype'", null);
   1617         assertNetworkNotified(true);
   1618 
   1619         // Should not be able to change IS_PRIMARY and IS_SUPER_PRIMARY by the above update
   1620         values.put(Data.IS_PRIMARY, 1);
   1621         values.put(Data.IS_SUPER_PRIMARY, 1);
   1622         assertStoredValues(uri, values);
   1623 
   1624         int count = mResolver.delete(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId
   1625                 + " AND " + Data.MIMETYPE + "='testmimetype'", null);
   1626         assertEquals(1, count);
   1627         assertEquals(0, getCount(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId
   1628                         + " AND " + Data.MIMETYPE + "='testmimetype'", null));
   1629         assertNetworkNotified(true);
   1630     }
   1631 
   1632     public void testRawContactQuery() {
   1633         Account account1 = new Account("a", "b");
   1634         Account account2 = new Account("c", "d");
   1635         long rawContactId1 = createRawContact(account1);
   1636         long rawContactId2 = createRawContact(account2);
   1637 
   1638         Uri uri1 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account1);
   1639         Uri uri2 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account2);
   1640         assertEquals(1, getCount(uri1, null, null));
   1641         assertEquals(1, getCount(uri2, null, null));
   1642         assertStoredValue(uri1, RawContacts._ID, rawContactId1) ;
   1643         assertStoredValue(uri2, RawContacts._ID, rawContactId2) ;
   1644 
   1645         Uri rowUri1 = ContentUris.withAppendedId(uri1, rawContactId1);
   1646         Uri rowUri2 = ContentUris.withAppendedId(uri2, rawContactId2);
   1647         assertStoredValue(rowUri1, RawContacts._ID, rawContactId1) ;
   1648         assertStoredValue(rowUri2, RawContacts._ID, rawContactId2) ;
   1649     }
   1650 
   1651     public void testRawContactDeletion() {
   1652         long rawContactId = createRawContact(mAccount);
   1653         Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
   1654 
   1655         insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme (at) android.com");
   1656         insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme (at) android.com",
   1657                 StatusUpdates.AVAILABLE, null);
   1658         long contactId = queryContactId(rawContactId);
   1659 
   1660         assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY),
   1661                 null, null));
   1662         assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "="
   1663                 + rawContactId, null));
   1664 
   1665         mResolver.delete(uri, null, null);
   1666 
   1667         assertStoredValue(uri, RawContacts.DELETED, "1");
   1668         assertNetworkNotified(true);
   1669 
   1670         Uri permanentDeletionUri = setCallerIsSyncAdapter(uri, mAccount);
   1671         mResolver.delete(permanentDeletionUri, null, null);
   1672         assertEquals(0, getCount(uri, null, null));
   1673         assertEquals(0, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY),
   1674                 null, null));
   1675         assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "="
   1676                 + rawContactId, null));
   1677         assertEquals(0, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null));
   1678         assertNetworkNotified(false);
   1679     }
   1680 
   1681     public void testRawContactDeletionKeepingAggregateContact() {
   1682         long rawContactId1 = createRawContactWithName(mAccount);
   1683         long rawContactId2 = createRawContactWithName(mAccount);
   1684 
   1685         // Same name - should be aggregated
   1686         assertAggregated(rawContactId1, rawContactId2);
   1687 
   1688         long contactId = queryContactId(rawContactId1);
   1689 
   1690         Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1);
   1691         Uri permanentDeletionUri = setCallerIsSyncAdapter(uri, mAccount);
   1692         mResolver.delete(permanentDeletionUri, null, null);
   1693         assertEquals(0, getCount(uri, null, null));
   1694         assertEquals(1, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null));
   1695     }
   1696 
   1697     public void testRawContactDeletionWithAccounts() {
   1698         long rawContactId = createRawContact(mAccount);
   1699         Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
   1700 
   1701         insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme (at) android.com");
   1702         insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme (at) android.com",
   1703                 StatusUpdates.AVAILABLE, null);
   1704         assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY),
   1705                 null, null));
   1706         assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "="
   1707                 + rawContactId, null));
   1708 
   1709         // Do not delete if we are deleting with wrong account.
   1710         Uri deleteWithWrongAccountUri =
   1711             RawContacts.CONTENT_URI.buildUpon()
   1712                 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccountTwo.name)
   1713                 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccountTwo.type)
   1714                 .build();
   1715         mResolver.delete(deleteWithWrongAccountUri, null, null);
   1716 
   1717         assertStoredValue(uri, RawContacts.DELETED, "0");
   1718 
   1719         // Delete if we are deleting with correct account.
   1720         Uri deleteWithCorrectAccountUri =
   1721             RawContacts.CONTENT_URI.buildUpon()
   1722                 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccount.name)
   1723                 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccount.type)
   1724                 .build();
   1725         mResolver.delete(deleteWithCorrectAccountUri, null, null);
   1726 
   1727         assertStoredValue(uri, RawContacts.DELETED, "1");
   1728     }
   1729 
   1730     public void testAccountsUpdated() {
   1731         // This is to ensure we do not delete contacts with null, null (account name, type)
   1732         // accidentally.
   1733         long rawContactId3 = createRawContactWithName("James", "Sullivan");
   1734         insertPhoneNumber(rawContactId3, "5234567890");
   1735         Uri rawContact3 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId3);
   1736         assertEquals(1, getCount(RawContacts.CONTENT_URI, null, null));
   1737 
   1738         ContactsProvider2 cp = (ContactsProvider2) getProvider();
   1739         cp.onAccountsUpdated(new Account[]{mAccount, mAccountTwo});
   1740         assertEquals(1, getCount(RawContacts.CONTENT_URI, null, null));
   1741         assertStoredValue(rawContact3, RawContacts.ACCOUNT_NAME, "account1");
   1742         assertStoredValue(rawContact3, RawContacts.ACCOUNT_TYPE, "account type1");
   1743 
   1744         long rawContactId1 = createRawContact(mAccount);
   1745         insertEmail(rawContactId1, "account1 (at) email.com");
   1746         long rawContactId2 = createRawContact(mAccountTwo);
   1747         insertEmail(rawContactId2, "account2 (at) email.com");
   1748         insertImHandle(rawContactId2, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme (at) android.com");
   1749         insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme (at) android.com",
   1750                 StatusUpdates.AVAILABLE, null);
   1751 
   1752         cp.onAccountsUpdated(new Account[]{mAccount});
   1753         assertEquals(2, getCount(RawContacts.CONTENT_URI, null, null));
   1754         assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "="
   1755                 + rawContactId2, null));
   1756     }
   1757 
   1758     public void testAccountDeletion() {
   1759         Account readOnlyAccount = new Account("act", READ_ONLY_ACCOUNT_TYPE);
   1760         ContactsProvider2 cp = (ContactsProvider2) getProvider();
   1761         cp.onAccountsUpdated(new Account[]{readOnlyAccount, mAccount});
   1762 
   1763         long rawContactId1 = createRawContactWithName("John", "Doe", readOnlyAccount);
   1764         Uri photoUri1 = insertPhoto(rawContactId1);
   1765         long rawContactId2 = createRawContactWithName("john", "doe", mAccount);
   1766         Uri photoUri2 = insertPhoto(rawContactId2);
   1767         storeValue(photoUri2, Photo.IS_SUPER_PRIMARY, "1");
   1768 
   1769         assertAggregated(rawContactId1, rawContactId2);
   1770 
   1771         long contactId = queryContactId(rawContactId1);
   1772 
   1773         // The display name should come from the writable account
   1774         assertStoredValue(Uri.withAppendedPath(
   1775                 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
   1776                 Contacts.Data.CONTENT_DIRECTORY),
   1777                 Contacts.DISPLAY_NAME, "john doe");
   1778 
   1779         // The photo should be the one we marked as super-primary
   1780         assertStoredValue(Contacts.CONTENT_URI, contactId,
   1781                 Contacts.PHOTO_ID, ContentUris.parseId(photoUri2));
   1782 
   1783         // Remove the writable account
   1784         cp.onAccountsUpdated(new Account[]{readOnlyAccount});
   1785 
   1786         // The display name should come from the remaining account
   1787         assertStoredValue(Uri.withAppendedPath(
   1788                 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
   1789                 Contacts.Data.CONTENT_DIRECTORY),
   1790                 Contacts.DISPLAY_NAME, "John Doe");
   1791 
   1792         // The photo should be the remaining one
   1793         assertStoredValue(Contacts.CONTENT_URI, contactId,
   1794                 Contacts.PHOTO_ID, ContentUris.parseId(photoUri1));
   1795 
   1796     }
   1797 
   1798     public void testContactDeletion() {
   1799         long rawContactId1 = createRawContactWithName("John", "Doe");
   1800         long rawContactId2 = createRawContactWithName("John", "Doe");
   1801 
   1802         long contactId = queryContactId(rawContactId1);
   1803 
   1804         mResolver.delete(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), null, null);
   1805 
   1806         assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1),
   1807                 RawContacts.DELETED, "1");
   1808         assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2),
   1809                 RawContacts.DELETED, "1");
   1810     }
   1811 
   1812     public void testMarkAsDirtyParameter() {
   1813         long rawContactId = createRawContact(mAccount);
   1814         Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
   1815 
   1816         Uri uri = insertStructuredName(rawContactId, "John", "Doe");
   1817         clearDirty(rawContactUri);
   1818         Uri updateUri = setCallerIsSyncAdapter(uri, mAccount);
   1819 
   1820         ContentValues values = new ContentValues();
   1821         values.put(StructuredName.FAMILY_NAME, "Dough");
   1822         mResolver.update(updateUri, values, null, null);
   1823         assertStoredValue(uri, StructuredName.FAMILY_NAME, "Dough");
   1824         assertDirty(rawContactUri, false);
   1825         assertNetworkNotified(false);
   1826     }
   1827 
   1828     public void testRawContactDirtyAndVersion() {
   1829         final long rawContactId = createRawContact(mAccount);
   1830         Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId);
   1831         assertDirty(uri, false);
   1832         long version = getVersion(uri);
   1833 
   1834         ContentValues values = new ContentValues();
   1835         values.put(ContactsContract.RawContacts.DIRTY, 0);
   1836         values.put(ContactsContract.RawContacts.SEND_TO_VOICEMAIL, 1);
   1837         values.put(ContactsContract.RawContacts.AGGREGATION_MODE,
   1838                 RawContacts.AGGREGATION_MODE_IMMEDIATE);
   1839         values.put(ContactsContract.RawContacts.STARRED, 1);
   1840         assertEquals(1, mResolver.update(uri, values, null, null));
   1841         assertEquals(version, getVersion(uri));
   1842 
   1843         assertDirty(uri, false);
   1844         assertNetworkNotified(false);
   1845 
   1846         Uri emailUri = insertEmail(rawContactId, "goo (at) woo.com");
   1847         assertDirty(uri, true);
   1848         assertNetworkNotified(true);
   1849         ++version;
   1850         assertEquals(version, getVersion(uri));
   1851         clearDirty(uri);
   1852 
   1853         values = new ContentValues();
   1854         values.put(Email.DATA, "goo (at) hoo.com");
   1855         mResolver.update(emailUri, values, null, null);
   1856         assertDirty(uri, true);
   1857         assertNetworkNotified(true);
   1858         ++version;
   1859         assertEquals(version, getVersion(uri));
   1860         clearDirty(uri);
   1861 
   1862         mResolver.delete(emailUri, null, null);
   1863         assertDirty(uri, true);
   1864         assertNetworkNotified(true);
   1865         ++version;
   1866         assertEquals(version, getVersion(uri));
   1867     }
   1868 
   1869     public void testRawContactClearDirty() {
   1870         final long rawContactId = createRawContact(mAccount);
   1871         Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
   1872                 rawContactId);
   1873         long version = getVersion(uri);
   1874         insertEmail(rawContactId, "goo (at) woo.com");
   1875         assertDirty(uri, true);
   1876         version++;
   1877         assertEquals(version, getVersion(uri));
   1878 
   1879         clearDirty(uri);
   1880         assertDirty(uri, false);
   1881         assertEquals(version, getVersion(uri));
   1882     }
   1883 
   1884     public void testRawContactDeletionSetsDirty() {
   1885         final long rawContactId = createRawContact(mAccount);
   1886         Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
   1887                 rawContactId);
   1888         long version = getVersion(uri);
   1889         clearDirty(uri);
   1890         assertDirty(uri, false);
   1891 
   1892         mResolver.delete(uri, null, null);
   1893         assertStoredValue(uri, RawContacts.DELETED, "1");
   1894         assertDirty(uri, true);
   1895         assertNetworkNotified(true);
   1896         version++;
   1897         assertEquals(version, getVersion(uri));
   1898     }
   1899 
   1900     public void testDeleteContactWithoutName() {
   1901         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues());
   1902         long rawContactId = ContentUris.parseId(rawContactUri);
   1903 
   1904         Uri phoneUri = insertPhoneNumber(rawContactId, "555-123-45678", true);
   1905 
   1906         long contactId = queryContactId(rawContactId);
   1907         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1908         Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri);
   1909 
   1910         int numDeleted = mResolver.delete(lookupUri, null, null);
   1911         assertEquals(1, numDeleted);
   1912     }
   1913 
   1914     public void testDeleteContactWithoutAnyData() {
   1915         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues());
   1916         long rawContactId = ContentUris.parseId(rawContactUri);
   1917 
   1918         long contactId = queryContactId(rawContactId);
   1919         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1920         Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri);
   1921 
   1922         int numDeleted = mResolver.delete(lookupUri, null, null);
   1923         assertEquals(1, numDeleted);
   1924     }
   1925 
   1926     public void testDeleteContactWithEscapedUri() {
   1927         ContentValues values = new ContentValues();
   1928         values.put(RawContacts.SOURCE_ID, "!@#$%^&*()_+=-/.,<>?;'\":[]}{\\|`~");
   1929         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
   1930         long rawContactId = ContentUris.parseId(rawContactUri);
   1931 
   1932         long contactId = queryContactId(rawContactId);
   1933         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1934         Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri);
   1935         assertEquals(1, mResolver.delete(lookupUri, null, null));
   1936     }
   1937 
   1938     public void testQueryContactWithEscapedUri() {
   1939         ContentValues values = new ContentValues();
   1940         values.put(RawContacts.SOURCE_ID, "!@#$%^&*()_+=-/.,<>?;'\":[]}{\\|`~");
   1941         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
   1942         long rawContactId = ContentUris.parseId(rawContactUri);
   1943 
   1944         long contactId = queryContactId(rawContactId);
   1945         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1946         Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri);
   1947         Cursor c = mResolver.query(lookupUri, null, null, null, "");
   1948         assertEquals(1, c.getCount());
   1949         c.close();
   1950     }
   1951 
   1952     public void testGetPhotoUri() {
   1953         ContentValues values = new ContentValues();
   1954         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
   1955         long rawContactId = ContentUris.parseId(rawContactUri);
   1956         insertStructuredName(rawContactId, "John", "Doe");
   1957         Uri photoUri = insertPhoto(rawContactId);
   1958 
   1959         Uri twigUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI,
   1960                 queryContactId(rawContactId)), Contacts.Photo.CONTENT_DIRECTORY);
   1961 
   1962         long twigId = Long.parseLong(getStoredValue(twigUri, Data._ID));
   1963         assertEquals(ContentUris.parseId(photoUri), twigId);
   1964     }
   1965 
   1966     public void testOpenAssertFileDescriptorForPhoto() throws Exception {
   1967         long rawContactId = createRawContact();
   1968         Uri photoUri = insertPhoto(rawContactId);
   1969         AssetFileDescriptor fd = mResolver.openAssetFileDescriptor(photoUri, "r");
   1970         assertEquals(loadTestPhoto().length, fd.getLength());
   1971 
   1972         Uri contactPhotoUri = Uri.withAppendedPath(
   1973                 ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(rawContactId)),
   1974                 Contacts.Photo.CONTENT_DIRECTORY);
   1975         fd = mResolver.openAssetFileDescriptor(contactPhotoUri, "r");
   1976         assertEquals(loadTestPhoto().length, fd.getLength());
   1977     }
   1978 
   1979     public void testSuperPrimaryPhoto() {
   1980         long rawContactId1 = createRawContact(new Account("a", "a"));
   1981         Uri photoUri1 = insertPhoto(rawContactId1);
   1982         long photoId1 = ContentUris.parseId(photoUri1);
   1983 
   1984         long rawContactId2 = createRawContact(new Account("b", "b"));
   1985         Uri photoUri2 = insertPhoto(rawContactId2);
   1986         long photoId2 = ContentUris.parseId(photoUri2);
   1987 
   1988         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1989                 rawContactId1, rawContactId2);
   1990 
   1991         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
   1992                 queryContactId(rawContactId1));
   1993         assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1);
   1994 
   1995         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
   1996                 rawContactId1, rawContactId2);
   1997 
   1998         ContentValues values = new ContentValues();
   1999         values.put(Data.IS_SUPER_PRIMARY, 1);
   2000         mResolver.update(photoUri2, values, null, null);
   2001 
   2002         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   2003                 rawContactId1, rawContactId2);
   2004         contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
   2005                 queryContactId(rawContactId1));
   2006         assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId2);
   2007 
   2008         mResolver.update(photoUri1, values, null, null);
   2009         assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1);
   2010     }
   2011 
   2012     public void testUpdatePhoto() {
   2013         ContentValues values = new ContentValues();
   2014         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
   2015         long rawContactId = ContentUris.parseId(rawContactUri);
   2016         insertStructuredName(rawContactId, "John", "Doe");
   2017 
   2018         Uri twigUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI,
   2019                 queryContactId(rawContactId)), Contacts.Photo.CONTENT_DIRECTORY);
   2020 
   2021         values.clear();
   2022         values.put(Data.RAW_CONTACT_ID, rawContactId);
   2023         values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
   2024         values.putNull(Photo.PHOTO);
   2025         Uri dataUri = mResolver.insert(Data.CONTENT_URI, values);
   2026         long photoId = ContentUris.parseId(dataUri);
   2027 
   2028         assertNull(getStoredValue(twigUri, Data._ID));
   2029 
   2030         values.clear();
   2031         values.put(Photo.PHOTO, loadTestPhoto());
   2032         mResolver.update(dataUri, values, null, null);
   2033         assertNetworkNotified(true);
   2034 
   2035         long twigId = Long.parseLong(getStoredValue(twigUri, Data._ID));
   2036         assertEquals(photoId, twigId);
   2037     }
   2038 
   2039     public void testUpdateRawContactDataPhoto() {
   2040         // setup a contact with a null photo
   2041         ContentValues values = new ContentValues();
   2042         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
   2043         long rawContactId = ContentUris.parseId(rawContactUri);
   2044 
   2045         // setup a photo
   2046         values.put(Data.RAW_CONTACT_ID, rawContactId);
   2047         values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
   2048         values.putNull(Photo.PHOTO);
   2049 
   2050         // try to do an update before insert should return count == 0
   2051         Uri dataUri = Uri.withAppendedPath(
   2052                 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
   2053                 RawContacts.Data.CONTENT_DIRECTORY);
   2054         assertEquals(0, mResolver.update(dataUri, values, Data.MIMETYPE + "=?",
   2055                 new String[] {Photo.CONTENT_ITEM_TYPE}));
   2056 
   2057         mResolver.insert(Data.CONTENT_URI, values);
   2058 
   2059         // save a photo to the db
   2060         values.clear();
   2061         values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
   2062         values.put(Photo.PHOTO, loadTestPhoto());
   2063         assertEquals(1, mResolver.update(dataUri, values, Data.MIMETYPE + "=?",
   2064                 new String[] {Photo.CONTENT_ITEM_TYPE}));
   2065 
   2066         // verify the photo
   2067         Cursor storedPhoto = mResolver.query(dataUri, new String[] {Photo.PHOTO},
   2068                 Data.MIMETYPE + "=?", new String[] {Photo.CONTENT_ITEM_TYPE}, null);
   2069         storedPhoto.moveToFirst();
   2070         MoreAsserts.assertEquals(loadTestPhoto(), storedPhoto.getBlob(0));
   2071         storedPhoto.close();
   2072     }
   2073 
   2074     public void testUpdateRawContactSetStarred() {
   2075         long rawContactId1 = createRawContactWithName();
   2076         Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1);
   2077         long rawContactId2 = createRawContactWithName();
   2078         Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2);
   2079 
   2080         assertAggregated(rawContactId1, rawContactId2);
   2081 
   2082         long contactId = queryContactId(rawContactId1);
   2083         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   2084         assertStoredValue(contactUri, Contacts.STARRED, "0");
   2085 
   2086         ContentValues values = new ContentValues();
   2087         values.put(RawContacts.STARRED, "1");
   2088 
   2089         mResolver.update(rawContactUri1, values, null, null);
   2090 
   2091         assertStoredValue(rawContactUri1, RawContacts.STARRED, "1");
   2092         assertStoredValue(rawContactUri2, RawContacts.STARRED, "0");
   2093         assertStoredValue(contactUri, Contacts.STARRED, "1");
   2094 
   2095         values.put(RawContacts.STARRED, "0");
   2096         mResolver.update(rawContactUri1, values, null, null);
   2097 
   2098         assertStoredValue(rawContactUri1, RawContacts.STARRED, "0");
   2099         assertStoredValue(rawContactUri2, RawContacts.STARRED, "0");
   2100         assertStoredValue(contactUri, Contacts.STARRED, "0");
   2101 
   2102         values.put(Contacts.STARRED, "1");
   2103         mResolver.update(contactUri, values, null, null);
   2104 
   2105         assertStoredValue(rawContactUri1, RawContacts.STARRED, "1");
   2106         assertStoredValue(rawContactUri2, RawContacts.STARRED, "1");
   2107         assertStoredValue(contactUri, Contacts.STARRED, "1");
   2108     }
   2109 
   2110     public void testLiveFolders() {
   2111         long rawContactId1 = createRawContactWithName("James", "Sullivan");
   2112         insertPhoneNumber(rawContactId1, "5234567890");
   2113         long contactId1 = queryContactId(rawContactId1);
   2114 
   2115         long rawContactId2 = createRawContactWithName("Mike", "Wazowski");
   2116         long contactId2 = queryContactId(rawContactId2);
   2117         storeValue(Contacts.CONTENT_URI, contactId2, Contacts.STARRED, "1");
   2118 
   2119         long rawContactId3 = createRawContactWithName("Randall", "Boggs");
   2120         long contactId3 = queryContactId(rawContactId3);
   2121         long groupId = createGroup(NO_ACCOUNT, "src1", "VIP");
   2122         insertGroupMembership(rawContactId3, groupId);
   2123 
   2124         assertLiveFolderContents(
   2125                 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI,
   2126                         "live_folders/contacts"),
   2127                 contactId1, "James Sullivan",
   2128                 contactId2, "Mike Wazowski",
   2129                 contactId3, "Randall Boggs");
   2130 
   2131         assertLiveFolderContents(
   2132                 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI,
   2133                         "live_folders/contacts_with_phones"),
   2134                 contactId1, "James Sullivan");
   2135 
   2136         assertLiveFolderContents(
   2137                 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI,
   2138                         "live_folders/favorites"),
   2139                 contactId2, "Mike Wazowski");
   2140 
   2141         assertLiveFolderContents(
   2142                 Uri.withAppendedPath(Uri.withAppendedPath(ContactsContract.AUTHORITY_URI,
   2143                         "live_folders/contacts"), Uri.encode("VIP")),
   2144                 contactId3, "Randall Boggs");
   2145     }
   2146 
   2147     private void assertLiveFolderContents(Uri uri, Object... expected) {
   2148         Cursor c = mResolver.query(uri, new String[]{LiveFolders._ID, LiveFolders.NAME},
   2149                 null, null, LiveFolders._ID);
   2150         assertEquals(expected.length/2, c.getCount());
   2151         for (int i = 0; i < expected.length/2; i++) {
   2152             assertTrue(c.moveToNext());
   2153             assertEquals(((Long)expected[i * 2]).longValue(), c.getLong(0));
   2154             assertEquals(expected[i * 2 + 1], c.getString(1));
   2155         }
   2156         c.close();
   2157     }
   2158 
   2159     public void testContactCounts() {
   2160         Uri uri = Contacts.CONTENT_URI.buildUpon()
   2161                 .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build();
   2162 
   2163         createRawContact();
   2164         createRawContactWithName("James", "Sullivan");
   2165         createRawContactWithName("The Abominable", "Snowman");
   2166         createRawContactWithName("Mike", "Wazowski");
   2167         createRawContactWithName("randall", "boggs");
   2168         createRawContactWithName("Boo", null);
   2169         createRawContactWithName("Mary", null);
   2170         createRawContactWithName("Roz", null);
   2171 
   2172         Cursor cursor = mResolver.query(uri,
   2173                 new String[]{Contacts.DISPLAY_NAME},
   2174                 null, null, Contacts.SORT_KEY_PRIMARY + " COLLATE LOCALIZED");
   2175 
   2176         assertFirstLetterValues(cursor, null, "B", "J", "M", "R", "T");
   2177         assertFirstLetterCounts(cursor,    1,   1,   1,   2,   2,   1);
   2178         cursor.close();
   2179 
   2180         cursor = mResolver.query(uri,
   2181                 new String[]{Contacts.DISPLAY_NAME},
   2182                 null, null, Contacts.SORT_KEY_ALTERNATIVE + " COLLATE LOCALIZED DESC");
   2183 
   2184         assertFirstLetterValues(cursor, "W", "S", "R", "M", "B", null);
   2185         assertFirstLetterCounts(cursor,   1,   2,   1,   1,   2,    1);
   2186         cursor.close();
   2187     }
   2188 
   2189     private void assertFirstLetterValues(Cursor cursor, String... expected) {
   2190         String[] actual = cursor.getExtras()
   2191                 .getStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES);
   2192         MoreAsserts.assertEquals(expected, actual);
   2193     }
   2194 
   2195     private void assertFirstLetterCounts(Cursor cursor, int... expected) {
   2196         int[] actual = cursor.getExtras()
   2197                 .getIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS);
   2198         MoreAsserts.assertEquals(expected, actual);
   2199     }
   2200 
   2201     public void testReadBooleanQueryParameter() {
   2202         assertBooleanUriParameter("foo:bar", "bool", true, true);
   2203         assertBooleanUriParameter("foo:bar", "bool", false, false);
   2204         assertBooleanUriParameter("foo:bar?bool=0", "bool", true, false);
   2205         assertBooleanUriParameter("foo:bar?bool=1", "bool", false, true);
   2206         assertBooleanUriParameter("foo:bar?bool=false", "bool", true, false);
   2207         assertBooleanUriParameter("foo:bar?bool=true", "bool", false, true);
   2208         assertBooleanUriParameter("foo:bar?bool=FaLsE", "bool", true, false);
   2209         assertBooleanUriParameter("foo:bar?bool=false&some=some", "bool", true, false);
   2210         assertBooleanUriParameter("foo:bar?bool=1&some=some", "bool", false, true);
   2211         assertBooleanUriParameter("foo:bar?some=bool", "bool", true, true);
   2212         assertBooleanUriParameter("foo:bar?bool", "bool", true, true);
   2213     }
   2214 
   2215     private void assertBooleanUriParameter(String uriString, String parameter,
   2216             boolean defaultValue, boolean expectedValue) {
   2217         assertEquals(expectedValue, ContactsProvider2.readBooleanQueryParameter(
   2218                 Uri.parse(uriString), parameter, defaultValue));
   2219     }
   2220 
   2221     public void testGetQueryParameter() {
   2222         assertQueryParameter("foo:bar", "param", null);
   2223         assertQueryParameter("foo:bar?param", "param", null);
   2224         assertQueryParameter("foo:bar?param=", "param", "");
   2225         assertQueryParameter("foo:bar?param=val", "param", "val");
   2226         assertQueryParameter("foo:bar?param=val&some=some", "param", "val");
   2227         assertQueryParameter("foo:bar?some=some&param=val", "param", "val");
   2228         assertQueryParameter("foo:bar?some=some&param=val&else=else", "param", "val");
   2229         assertQueryParameter("foo:bar?param=john%40doe.com", "param", "john (at) doe.com");
   2230     }
   2231 
   2232     public void testMissingAccountTypeParameter() {
   2233         // Try querying for RawContacts only using ACCOUNT_NAME
   2234         final Uri queryUri = RawContacts.CONTENT_URI.buildUpon().appendQueryParameter(
   2235                 RawContacts.ACCOUNT_NAME, "lolwut").build();
   2236         try {
   2237             final Cursor cursor = mResolver.query(queryUri, null, null, null, null);
   2238             fail("Able to query with incomplete account query parameters");
   2239         } catch (IllegalArgumentException e) {
   2240             // Expected behavior.
   2241         }
   2242     }
   2243 
   2244     public void testInsertInconsistentAccountType() {
   2245         // Try inserting RawContact with inconsistent Accounts
   2246         final Account red = new Account("red", "red");
   2247         final Account blue = new Account("blue", "blue");
   2248 
   2249         final ContentValues values = new ContentValues();
   2250         values.put(RawContacts.ACCOUNT_NAME, red.name);
   2251         values.put(RawContacts.ACCOUNT_TYPE, red.type);
   2252 
   2253         final Uri insertUri = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, blue);
   2254         try {
   2255             mResolver.insert(insertUri, values);
   2256             fail("Able to insert RawContact with inconsistent account details");
   2257         } catch (IllegalArgumentException e) {
   2258             // Expected behavior.
   2259         }
   2260     }
   2261 
   2262     public void testProviderStatus() throws Exception {
   2263         Cursor cursor = mResolver.query(ProviderStatus.CONTENT_URI,
   2264                 new String[]{ProviderStatus.DATA1, ProviderStatus.STATUS}, null, null, null);
   2265         assertTrue(cursor.moveToFirst());
   2266         assertEquals(0, cursor.getLong(0));
   2267         assertEquals(ProviderStatus.STATUS_NORMAL, cursor.getInt(1));
   2268         cursor.close();
   2269     }
   2270 
   2271     public void testProperties() throws Exception {
   2272         ContactsProvider2 provider = (ContactsProvider2)getProvider();
   2273         ContactsDatabaseHelper helper = (ContactsDatabaseHelper)provider.getDatabaseHelper();
   2274         assertNull(helper.getProperty("non-existent", null));
   2275         assertEquals("default", helper.getProperty("non-existent", "default"));
   2276 
   2277         helper.setProperty("existent1", "string1");
   2278         helper.setProperty("existent2", "string2");
   2279         assertEquals("string1", helper.getProperty("existent1", "default"));
   2280         assertEquals("string2", helper.getProperty("existent2", "default"));
   2281         helper.setProperty("existent1", null);
   2282         assertEquals("default", helper.getProperty("existent1", "default"));
   2283     }
   2284 
   2285     private class VCardTestUriCreator {
   2286         private String mLookup1;
   2287         private String mLookup2;
   2288 
   2289         public VCardTestUriCreator(String lookup1, String lookup2) {
   2290             super();
   2291             mLookup1 = lookup1;
   2292             mLookup2 = lookup2;
   2293         }
   2294 
   2295         public Uri getUri1() {
   2296             return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup1);
   2297         }
   2298 
   2299         public Uri getUri2() {
   2300             return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup2);
   2301         }
   2302 
   2303         public Uri getCombinedUri() {
   2304             return Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI,
   2305                     Uri.encode(mLookup1 + ":" + mLookup2));
   2306         }
   2307     }
   2308 
   2309     private VCardTestUriCreator createVCardTestContacts() {
   2310         final long rawContactId1 = createRawContact(mAccount, RawContacts.SOURCE_ID, "4:12");
   2311         insertStructuredName(rawContactId1, "John", "Doe");
   2312 
   2313         final long rawContactId2 = createRawContact(mAccount, RawContacts.SOURCE_ID, "3:4%121");
   2314         insertStructuredName(rawContactId2, "Jane", "Doh");
   2315 
   2316         final long contactId1 = queryContactId(rawContactId1);
   2317         final long contactId2 = queryContactId(rawContactId2);
   2318         final Uri contact1Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId1);
   2319         final Uri contact2Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId2);
   2320         final String lookup1 =
   2321             Uri.encode(Contacts.getLookupUri(mResolver, contact1Uri).getPathSegments().get(2));
   2322         final String lookup2 =
   2323             Uri.encode(Contacts.getLookupUri(mResolver, contact2Uri).getPathSegments().get(2));
   2324         return new VCardTestUriCreator(lookup1, lookup2);
   2325     }
   2326 
   2327     public void testQueryMultiVCard() {
   2328         // No need to create any contacts here, because the query for multiple vcards
   2329         // does not go into the database at all
   2330         Uri uri = Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI, Uri.encode("123:456"));
   2331         Cursor cursor = mResolver.query(uri, null, null, null, null);
   2332         assertEquals(1, cursor.getCount());
   2333         assertTrue(cursor.moveToFirst());
   2334         assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE)));
   2335         String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
   2336 
   2337         // The resulting name contains date and time. Ensure that before and after are correct
   2338         assertTrue(filename.startsWith("vcards_"));
   2339         assertTrue(filename.endsWith(".vcf"));
   2340         cursor.close();
   2341     }
   2342 
   2343     public void testQueryFileSingleVCard() {
   2344         final VCardTestUriCreator contacts = createVCardTestContacts();
   2345 
   2346         {
   2347             Cursor cursor = mResolver.query(contacts.getUri1(), null, null, null, null);
   2348             assertEquals(1, cursor.getCount());
   2349             assertTrue(cursor.moveToFirst());
   2350             assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE)));
   2351             String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
   2352             assertEquals("John Doe.vcf", filename);
   2353             cursor.close();
   2354         }
   2355 
   2356         {
   2357             Cursor cursor = mResolver.query(contacts.getUri2(), null, null, null, null);
   2358             assertEquals(1, cursor.getCount());
   2359             assertTrue(cursor.moveToFirst());
   2360             assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE)));
   2361             String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
   2362             assertEquals("Jane Doh.vcf", filename);
   2363             cursor.close();
   2364         }
   2365     }
   2366 
   2367 
   2368     public void testOpenAssetFileMultiVCard() throws IOException {
   2369         final VCardTestUriCreator contacts = createVCardTestContacts();
   2370 
   2371         final AssetFileDescriptor descriptor =
   2372             mResolver.openAssetFileDescriptor(contacts.getCombinedUri(), "r");
   2373         final FileInputStream inputStream = descriptor.createInputStream();
   2374         String data = readToEnd(inputStream);
   2375         inputStream.close();
   2376         descriptor.close();
   2377 
   2378         // Ensure that the resulting VCard has both contacts
   2379         assertTrue(data.contains("N:Doe;John;;;"));
   2380         assertTrue(data.contains("N:Doh;Jane;;;"));
   2381     }
   2382 
   2383     public void testOpenAssetFileSingleVCard() throws IOException {
   2384         final VCardTestUriCreator contacts = createVCardTestContacts();
   2385 
   2386         // Ensure that the right VCard is being created in each case
   2387         {
   2388             final AssetFileDescriptor descriptor =
   2389                 mResolver.openAssetFileDescriptor(contacts.getUri1(), "r");
   2390             final FileInputStream inputStream = descriptor.createInputStream();
   2391             final String data = readToEnd(inputStream);
   2392             assertTrue(data.contains("N:Doe;John;;;"));
   2393             assertFalse(data.contains("N:Doh;Jane;;;"));
   2394 
   2395             inputStream.close();
   2396             descriptor.close();
   2397         }
   2398 
   2399         {
   2400             final AssetFileDescriptor descriptor =
   2401                 mResolver.openAssetFileDescriptor(contacts.getUri2(), "r");
   2402             final FileInputStream inputStream = descriptor.createInputStream();
   2403             final String data = readToEnd(inputStream);
   2404             inputStream.close();
   2405             descriptor.close();
   2406 
   2407             assertFalse(data.contains("N:Doe;John;;;"));
   2408             assertTrue(data.contains("N:Doh;Jane;;;"));
   2409         }
   2410     }
   2411 
   2412     private String readToEnd(FileInputStream inputStream) {
   2413         try {
   2414             int ch;
   2415             StringBuilder stringBuilder = new StringBuilder();
   2416             while ((ch = inputStream.read()) != -1)
   2417                 stringBuilder.append((char)ch);
   2418             return stringBuilder.toString();
   2419         } catch (IOException e) {
   2420             return null;
   2421         }
   2422     }
   2423 
   2424     private void assertQueryParameter(String uriString, String parameter, String expectedValue) {
   2425         assertEquals(expectedValue, ContactsProvider2.getQueryParameter(
   2426                 Uri.parse(uriString), parameter));
   2427     }
   2428 
   2429     private long createContact(ContentValues values, String firstName, String givenName,
   2430             String phoneNumber, String email, int presenceStatus, int timesContacted, int starred,
   2431             long groupId) {
   2432         return queryContactId(createRawContact(values, firstName, givenName, phoneNumber, email,
   2433                 presenceStatus, timesContacted, starred, groupId));
   2434     }
   2435 
   2436     private long createRawContact(ContentValues values, String firstName, String givenName,
   2437             String phoneNumber, String email, int presenceStatus, int timesContacted, int starred,
   2438             long groupId) {
   2439         long rawContactId = createRawContact(values, phoneNumber, email, presenceStatus,
   2440                 timesContacted, starred, groupId);
   2441         insertStructuredName(rawContactId, firstName, givenName);
   2442         return rawContactId;
   2443     }
   2444 
   2445     private long createRawContact(ContentValues values, String phoneNumber, String email,
   2446             int presenceStatus, int timesContacted, int starred, long groupId) {
   2447         values.put(RawContacts.STARRED, starred);
   2448         values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
   2449         values.put(RawContacts.CUSTOM_RINGTONE, "beethoven5");
   2450         values.put(RawContacts.LAST_TIME_CONTACTED, 12345);
   2451         values.put(RawContacts.TIMES_CONTACTED, timesContacted);
   2452         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
   2453         long rawContactId = ContentUris.parseId(rawContactUri);
   2454         Uri photoUri = insertPhoto(rawContactId);
   2455         long photoId = ContentUris.parseId(photoUri);
   2456         values.put(Contacts.PHOTO_ID, photoId);
   2457         insertPhoneNumber(rawContactId, phoneNumber);
   2458         insertEmail(rawContactId, email);
   2459 
   2460         insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, email, presenceStatus, "hacking");
   2461 
   2462         if (groupId != 0) {
   2463             insertGroupMembership(rawContactId, groupId);
   2464         }
   2465         return rawContactId;
   2466     }
   2467 
   2468     private void putDataValues(ContentValues values, long rawContactId) {
   2469         values.put(Data.RAW_CONTACT_ID, rawContactId);
   2470         values.put(Data.MIMETYPE, "testmimetype");
   2471         values.put(Data.RES_PACKAGE, "oldpackage");
   2472         values.put(Data.IS_PRIMARY, 1);
   2473         values.put(Data.IS_SUPER_PRIMARY, 1);
   2474         values.put(Data.DATA1, "one");
   2475         values.put(Data.DATA2, "two");
   2476         values.put(Data.DATA3, "three");
   2477         values.put(Data.DATA4, "four");
   2478         values.put(Data.DATA5, "five");
   2479         values.put(Data.DATA6, "six");
   2480         values.put(Data.DATA7, "seven");
   2481         values.put(Data.DATA8, "eight");
   2482         values.put(Data.DATA9, "nine");
   2483         values.put(Data.DATA10, "ten");
   2484         values.put(Data.DATA11, "eleven");
   2485         values.put(Data.DATA12, "twelve");
   2486         values.put(Data.DATA13, "thirteen");
   2487         values.put(Data.DATA14, "fourteen");
   2488         values.put(Data.DATA15, "fifteen");
   2489         values.put(Data.SYNC1, "sync1");
   2490         values.put(Data.SYNC2, "sync2");
   2491         values.put(Data.SYNC3, "sync3");
   2492         values.put(Data.SYNC4, "sync4");
   2493     }
   2494 }
   2495 
   2496