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