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.google.android.collect.Lists;
     20 
     21 import android.accounts.Account;
     22 import android.content.ContentProviderOperation;
     23 import android.content.ContentProviderResult;
     24 import android.content.ContentUris;
     25 import android.content.ContentValues;
     26 import android.database.Cursor;
     27 import android.net.Uri;
     28 import android.provider.ContactsContract;
     29 import android.provider.ContactsContract.AggregationExceptions;
     30 import android.provider.ContactsContract.Contacts;
     31 import android.provider.ContactsContract.Data;
     32 import android.provider.ContactsContract.RawContacts;
     33 import android.provider.ContactsContract.CommonDataKinds.Organization;
     34 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
     35 import android.test.suitebuilder.annotation.LargeTest;
     36 
     37 /**
     38  * Unit tests for {@link ContactAggregator}.
     39  *
     40  * Run the test like this:
     41  * <code>
     42  * adb shell am instrument -e class com.android.providers.contacts.ContactAggregatorTest -w \
     43  *         com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
     44  * </code>
     45  */
     46 @LargeTest
     47 public class ContactAggregatorTest extends BaseContactsProvider2Test {
     48 
     49     private static final Account ACCOUNT_1 = new Account("account_name_1", "account_type_1");
     50     private static final Account ACCOUNT_2 = new Account("account_name_2", "account_type_2");
     51     private static final Account ACCOUNT_3 = new Account("account_name_3", "account_type_3");
     52 
     53     private static final String[] AGGREGATION_EXCEPTION_PROJECTION = new String[] {
     54             AggregationExceptions.TYPE,
     55             AggregationExceptions.RAW_CONTACT_ID1,
     56             AggregationExceptions.RAW_CONTACT_ID2
     57     };
     58 
     59     public void testCrudAggregationExceptions() throws Exception {
     60         long rawContactId1 = createRawContactWithName("zz", "top");
     61         long rawContactId2 = createRawContactWithName("aa", "bottom");
     62 
     63         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
     64                 rawContactId1, rawContactId2);
     65 
     66         String selection = "(" + AggregationExceptions.RAW_CONTACT_ID1 + "=" + rawContactId1
     67                 + " AND " + AggregationExceptions.RAW_CONTACT_ID2 + "=" + rawContactId2
     68                 + ") OR (" + AggregationExceptions.RAW_CONTACT_ID1 + "=" + rawContactId2
     69                 + " AND " + AggregationExceptions.RAW_CONTACT_ID2 + "=" + rawContactId1 + ")";
     70 
     71         // Refetch the row we have just inserted
     72         Cursor c = mResolver.query(AggregationExceptions.CONTENT_URI,
     73                 AGGREGATION_EXCEPTION_PROJECTION, selection, null, null);
     74 
     75         assertTrue(c.moveToFirst());
     76         assertEquals(AggregationExceptions.TYPE_KEEP_TOGETHER, c.getInt(0));
     77         assertTrue((rawContactId1 == c.getLong(1) && rawContactId2 == c.getLong(2))
     78                 || (rawContactId2 == c.getLong(1) && rawContactId1 == c.getLong(2)));
     79         assertFalse(c.moveToNext());
     80         c.close();
     81 
     82         // Change from TYPE_KEEP_IN to TYPE_KEEP_OUT
     83         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
     84                 rawContactId1, rawContactId2);
     85 
     86         c = mResolver.query(AggregationExceptions.CONTENT_URI, AGGREGATION_EXCEPTION_PROJECTION,
     87                 selection, null, null);
     88 
     89         assertTrue(c.moveToFirst());
     90         assertEquals(AggregationExceptions.TYPE_KEEP_SEPARATE, c.getInt(0));
     91         assertTrue((rawContactId1 == c.getLong(1) && rawContactId2 == c.getLong(2))
     92                 || (rawContactId2 == c.getLong(1) && rawContactId1 == c.getLong(2)));
     93         assertFalse(c.moveToNext());
     94         c.close();
     95 
     96         // Delete the rule
     97         setAggregationException(AggregationExceptions.TYPE_AUTOMATIC,
     98                 rawContactId1, rawContactId2);
     99 
    100         // Verify that the row is gone
    101         c = mResolver.query(AggregationExceptions.CONTENT_URI, AGGREGATION_EXCEPTION_PROJECTION,
    102                 selection, null, null);
    103         assertFalse(c.moveToFirst());
    104         c.close();
    105     }
    106 
    107     public void testAggregationCreatesNewAggregate() {
    108         long rawContactId = createRawContact();
    109 
    110         Uri resultUri = insertStructuredName(rawContactId, "Johna", "Smitha");
    111 
    112         // Parse the URI and confirm that it contains an ID
    113         assertTrue(ContentUris.parseId(resultUri) != 0);
    114 
    115         long contactId = queryContactId(rawContactId);
    116         assertTrue(contactId != 0);
    117 
    118         String displayName = queryDisplayName(contactId);
    119         assertEquals("Johna Smitha", displayName);
    120     }
    121 
    122     public void testNonAggregationFromSameAccount() {
    123         long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
    124         long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
    125         assertNotAggregated(rawContactId1, rawContactId2);
    126     }
    127 
    128     public void testAggregationOfExactFullNameMatch() {
    129         long rawContactId1 = createRawContact(ACCOUNT_1);
    130         insertStructuredName(rawContactId1, "Johnb", "Smithb");
    131 
    132         long rawContactId2 = createRawContact(ACCOUNT_2);
    133         insertStructuredName(rawContactId2, "Johnb", "Smithb");
    134 
    135         assertAggregated(rawContactId1, rawContactId2, "Johnb Smithb");
    136     }
    137 
    138     public void testAggregationOfCaseInsensitiveFullNameMatch() {
    139         long rawContactId1 = createRawContact(ACCOUNT_1);
    140         insertStructuredName(rawContactId1, "Johnc", "Smithc");
    141 
    142         long rawContactId2 = createRawContact(ACCOUNT_2);
    143         insertStructuredName(rawContactId2, "Johnc", "smithc");
    144 
    145         assertAggregated(rawContactId1, rawContactId2, "Johnc Smithc");
    146     }
    147 
    148     public void testAggregationOfLastNameMatch() {
    149         long rawContactId1 = createRawContact(ACCOUNT_1);
    150         insertStructuredName(rawContactId1, null, "Johnd");
    151 
    152         long rawContactId2 = createRawContact(ACCOUNT_2);
    153         insertStructuredName(rawContactId2, null, "johnd");
    154 
    155         assertAggregated(rawContactId1, rawContactId2, "Johnd");
    156     }
    157 
    158     public void testNonAggregationOfFirstNameMatch() {
    159         long rawContactId1 = createRawContact(ACCOUNT_1);
    160         insertStructuredName(rawContactId1, "Johne", "Smithe");
    161 
    162         long rawContactId2 = createRawContact(ACCOUNT_2);
    163         insertStructuredName(rawContactId2, "Johne", null);
    164 
    165         assertNotAggregated(rawContactId1, rawContactId2);
    166     }
    167 
    168     // TODO: should this be allowed to match?
    169     public void testNonAggregationOfLastNameMatch() {
    170         long rawContactId1 = createRawContact(ACCOUNT_1);
    171         insertStructuredName(rawContactId1, "Johnf", "Smithf");
    172 
    173         long rawContactId2 = createRawContact(ACCOUNT_2);
    174         insertStructuredName(rawContactId2, null, "Smithf");
    175 
    176         assertNotAggregated(rawContactId1, rawContactId2);
    177     }
    178 
    179     public void testAggregationOfConcatenatedFullNameMatch() {
    180         long rawContactId1 = createRawContact(ACCOUNT_1);
    181         insertStructuredName(rawContactId1, "Johng", "Smithg");
    182 
    183         long rawContactId2 = createRawContact(ACCOUNT_2);
    184         insertStructuredName(rawContactId2, "johngsmithg", null);
    185 
    186         assertAggregated(rawContactId1, rawContactId2, "Johng Smithg");
    187     }
    188 
    189     public void testAggregationOfNormalizedFullNameMatch() {
    190         long rawContactId1 = createRawContact(ACCOUNT_1);
    191         insertStructuredName(rawContactId1, "H\u00e9l\u00e8ne", "Bj\u00f8rn");
    192 
    193         long rawContactId2 = createRawContact(ACCOUNT_2);
    194         insertStructuredName(rawContactId2, "helene bjorn", null);
    195 
    196         assertAggregated(rawContactId1, rawContactId2, "H\u00e9l\u00e8ne Bj\u00f8rn");
    197     }
    198 
    199     public void testAggregationOfNormalizedFullNameMatchWithReadOnlyAccount() {
    200         long rawContactId1 = createRawContact(new Account("acct", READ_ONLY_ACCOUNT_TYPE));
    201         insertStructuredName(rawContactId1, "H\u00e9l\u00e8ne", "Bj\u00f8rn");
    202 
    203         long rawContactId2 = createRawContact();
    204         insertStructuredName(rawContactId2, "helene bjorn", null);
    205 
    206         assertAggregated(rawContactId1, rawContactId2, "helene bjorn");
    207     }
    208 
    209     public void testAggregationOfNumericNames() {
    210         long rawContactId1 = createRawContact(ACCOUNT_1);
    211         insertStructuredName(rawContactId1, "123", null);
    212 
    213         long rawContactId2 = createRawContact(ACCOUNT_2);
    214         insertStructuredName(rawContactId2, "1-2-3", null);
    215 
    216         assertAggregated(rawContactId1, rawContactId2, "1-2-3");
    217     }
    218 
    219     public void testAggregationOfInconsistentlyParsedNames() {
    220         long rawContactId1 = createRawContact(ACCOUNT_1);
    221 
    222         ContentValues values = new ContentValues();
    223         values.put(StructuredName.DISPLAY_NAME, "604 Arizona Ave");
    224         values.put(StructuredName.GIVEN_NAME, "604");
    225         values.put(StructuredName.MIDDLE_NAME, "Arizona");
    226         values.put(StructuredName.FAMILY_NAME, "Ave");
    227         insertStructuredName(rawContactId1, values);
    228 
    229         long rawContactId2 = createRawContact(ACCOUNT_2);
    230         values.clear();
    231         values.put(StructuredName.DISPLAY_NAME, "604 Arizona Ave");
    232         values.put(StructuredName.GIVEN_NAME, "604");
    233         values.put(StructuredName.FAMILY_NAME, "Arizona Ave");
    234         insertStructuredName(rawContactId2, values);
    235 
    236         assertAggregated(rawContactId1, rawContactId2, "604 Arizona Ave");
    237     }
    238 
    239     public void testAggregationBasedOnMiddleName() {
    240         ContentValues values = new ContentValues();
    241         long rawContactId1 = createRawContact(ACCOUNT_1);
    242         values.put(StructuredName.GIVEN_NAME, "John");
    243         values.put(StructuredName.GIVEN_NAME, "Abigale");
    244         values.put(StructuredName.FAMILY_NAME, "James");
    245 
    246         insertStructuredName(rawContactId1, values);
    247 
    248         long rawContactId2 = createRawContact(ACCOUNT_2);
    249         values.clear();
    250         values.put(StructuredName.GIVEN_NAME, "John");
    251         values.put(StructuredName.GIVEN_NAME, "Marie");
    252         values.put(StructuredName.FAMILY_NAME, "James");
    253         insertStructuredName(rawContactId2, values);
    254 
    255         assertNotAggregated(rawContactId1, rawContactId2);
    256     }
    257 
    258     public void testAggregationBasedOnPhoneNumberNoNameData() {
    259         long rawContactId1 = createRawContact(ACCOUNT_1);
    260         insertPhoneNumber(rawContactId1, "(888)555-1231");
    261 
    262         long rawContactId2 = createRawContact(ACCOUNT_2);
    263         insertPhoneNumber(rawContactId2, "1(888)555-1231");
    264 
    265         assertAggregated(rawContactId1, rawContactId2);
    266     }
    267 
    268     public void testNonAggregationBasedOnPhoneNumberNoNameDataSameAccount() {
    269         long rawContactId1 = createRawContact(ACCOUNT_1);
    270         insertPhoneNumber(rawContactId1, "(888)555-1231");
    271 
    272         long rawContactId2 = createRawContact(ACCOUNT_2);
    273         insertPhoneNumber(rawContactId2, "1(888)555-1231");
    274 
    275         long rawContactId3 = createRawContact(ACCOUNT_1);
    276         insertPhoneNumber(rawContactId3, "888-555-1231");
    277 
    278         assertNotAggregated(rawContactId1, rawContactId2);
    279         assertNotAggregated(rawContactId1, rawContactId3);
    280         assertNotAggregated(rawContactId2, rawContactId3);
    281     }
    282 
    283     public void testAggregationBasedOnPhoneNumberWhenTargetAggregateHasNoName() {
    284         long rawContactId1 = createRawContact(ACCOUNT_1);
    285         insertPhoneNumber(rawContactId1, "(888)555-1232");
    286 
    287         long rawContactId2 = createRawContact(ACCOUNT_2);
    288         insertStructuredName(rawContactId2, "Johnl", "Smithl");
    289         insertPhoneNumber(rawContactId2, "1(888)555-1232");
    290 
    291         assertAggregated(rawContactId1, rawContactId2);
    292     }
    293 
    294     public void testAggregationBasedOnPhoneNumberWhenNewContactHasNoName() {
    295         long rawContactId1 = createRawContact(ACCOUNT_1);
    296         insertStructuredName(rawContactId1, "Johnm", "Smithm");
    297         insertPhoneNumber(rawContactId1, "(888)555-1233");
    298 
    299         long rawContactId2 = createRawContact(ACCOUNT_2);
    300         insertPhoneNumber(rawContactId2, "1(888)555-1233");
    301 
    302         assertAggregated(rawContactId1, rawContactId2);
    303     }
    304 
    305     public void testAggregationBasedOnPhoneNumberWithDifferentNames() {
    306         long rawContactId1 = createRawContact(ACCOUNT_1);
    307         insertStructuredName(rawContactId1, "Baby", "Bear");
    308         insertPhoneNumber(rawContactId1, "(888)555-1235");
    309 
    310         long rawContactId2 = createRawContact(ACCOUNT_2);
    311         insertStructuredName(rawContactId2, "Blind", "Mouse");
    312         insertPhoneNumber(rawContactId2, "1(888)555-1235");
    313 
    314         assertNotAggregated(rawContactId1, rawContactId2);
    315     }
    316 
    317     public void testAggregationBasedOnPhoneNumberWithJustFirstName() {
    318         long rawContactId1 = createRawContact(ACCOUNT_1);
    319         insertStructuredName(rawContactId1, "Chick", "Notnull");
    320         insertPhoneNumber(rawContactId1, "(888)555-1236");
    321 
    322         long rawContactId2 = createRawContact(ACCOUNT_2);
    323         insertStructuredName(rawContactId2, "Chick", null);
    324         insertPhoneNumber(rawContactId2, "1(888)555-1236");
    325 
    326         assertAggregated(rawContactId1, rawContactId2);
    327     }
    328 
    329     public void testAggregationBasedOnEmailNoNameData() {
    330         long rawContactId1 = createRawContact(ACCOUNT_1);
    331         insertEmail(rawContactId1, "lightning (at) android.com");
    332 
    333         long rawContactId2 = createRawContact(ACCOUNT_2);
    334         insertEmail(rawContactId2, "lightning (at) android.com");
    335 
    336         assertAggregated(rawContactId1, rawContactId2);
    337     }
    338 
    339     public void testAggregationBasedOnEmailWhenTargetAggregateHasNoName() {
    340         long rawContactId1 = createRawContact(ACCOUNT_1);
    341         insertEmail(rawContactId1, "mcqueen (at) android.com");
    342 
    343         long rawContactId2 = createRawContact(ACCOUNT_2);
    344         insertStructuredName(rawContactId2, "Lightning", "McQueen");
    345         insertEmail(rawContactId2, "mcqueen (at) android.com");
    346 
    347         assertAggregated(rawContactId1, rawContactId2, "Lightning McQueen");
    348     }
    349 
    350     public void testAggregationBasedOnEmailWhenNewContactHasNoName() {
    351         long rawContactId1 = createRawContact(ACCOUNT_1);
    352         insertStructuredName(rawContactId1, "Doc", "Hudson");
    353         insertEmail(rawContactId1, "doc (at) android.com");
    354 
    355         long rawContactId2 = createRawContact(ACCOUNT_2);
    356         insertEmail(rawContactId2, "doc (at) android.com");
    357 
    358         assertAggregated(rawContactId1, rawContactId2);
    359     }
    360 
    361     public void testAggregationBasedOnEmailWithDifferentNames() {
    362         long rawContactId1 = createRawContact(ACCOUNT_1);
    363         insertStructuredName(rawContactId1, "Chick", "Hicks");
    364         insertEmail(rawContactId1, "hicky (at) android.com");
    365 
    366         long rawContactId2 = createRawContact(ACCOUNT_2);
    367         insertStructuredName(rawContactId2, "Luigi", "Guido");
    368         insertEmail(rawContactId2, "hicky (at) android.com");
    369 
    370         assertNotAggregated(rawContactId1, rawContactId2);
    371     }
    372 
    373     public void testAggregationByCommonNicknameWithLastName() {
    374         long rawContactId1 = createRawContact(ACCOUNT_1);
    375         insertStructuredName(rawContactId1, "Bill", "Gore");
    376 
    377         long rawContactId2 = createRawContact(ACCOUNT_2);
    378         insertStructuredName(rawContactId2, "William", "Gore");
    379 
    380         assertAggregated(rawContactId1, rawContactId2, "William Gore");
    381     }
    382 
    383     public void testAggregationByCommonNicknameOnly() {
    384         long rawContactId1 = createRawContact(ACCOUNT_1);
    385         insertStructuredName(rawContactId1, "Lawrence", null);
    386 
    387         long rawContactId2 = createRawContact(ACCOUNT_2);
    388         insertStructuredName(rawContactId2, "Larry", null);
    389 
    390         assertAggregated(rawContactId1, rawContactId2, "Lawrence");
    391     }
    392 
    393     public void testAggregationByNicknameNoStructuredName() {
    394         long rawContactId1 = createRawContact(ACCOUNT_1);
    395         insertNickname(rawContactId1, "Frozone");
    396 
    397         long rawContactId2 = createRawContact(ACCOUNT_2);
    398         insertNickname(rawContactId2, "Frozone");
    399 
    400         assertAggregated(rawContactId1, rawContactId2);
    401     }
    402 
    403     public void testAggregationByNicknameWithDifferentNames() {
    404         long rawContactId1 = createRawContact(ACCOUNT_1);
    405         insertStructuredName(rawContactId1, "Helen", "Parr");
    406         insertNickname(rawContactId1, "Elastigirl");
    407 
    408         long rawContactId2 = createRawContact(ACCOUNT_2);
    409         insertStructuredName(rawContactId2, "Shawn", "Johnson");
    410         insertNickname(rawContactId2, "Elastigirl");
    411 
    412         assertNotAggregated(rawContactId1, rawContactId2);
    413     }
    414 
    415     public void testNonAggregationOnOrganization() {
    416         ContentValues values = new ContentValues();
    417         values.put(Organization.TITLE, "Monsters, Inc");
    418         long rawContactId1 = createRawContact(ACCOUNT_1);
    419         insertOrganization(rawContactId1, values);
    420         insertNickname(rawContactId1, "Boo");
    421 
    422         long rawContactId2 = createRawContact(ACCOUNT_2);
    423         insertOrganization(rawContactId2, values);
    424         insertNickname(rawContactId2, "Rendall");   // To force reaggregation
    425 
    426         assertNotAggregated(rawContactId1, rawContactId2);
    427     }
    428 
    429     public void testAggregationExceptionKeepIn() {
    430         long rawContactId1 = createRawContact(ACCOUNT_1);
    431         insertStructuredName(rawContactId1, "Johnk", "Smithk");
    432 
    433         long rawContactId2 = createRawContact(ACCOUNT_2);
    434         insertStructuredName(rawContactId2, "Johnkx", "Smithkx");
    435 
    436         long contactId1 = queryContactId(rawContactId1);
    437         long contactId2 = queryContactId(rawContactId2);
    438 
    439         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    440                 rawContactId1, rawContactId2);
    441 
    442         assertAggregated(rawContactId1, rawContactId2, "Johnkx Smithkx");
    443 
    444         // Assert that the empty aggregate got removed
    445         long newContactId1 = queryContactId(rawContactId1);
    446         if (contactId1 != newContactId1) {
    447             Cursor cursor = queryContact(contactId1);
    448             assertFalse(cursor.moveToFirst());
    449             cursor.close();
    450         } else {
    451             Cursor cursor = queryContact(contactId2);
    452             assertFalse(cursor.moveToFirst());
    453             cursor.close();
    454         }
    455     }
    456 
    457     public void testAggregationExceptionKeepOut() {
    458         long rawContactId1 = createRawContact(ACCOUNT_1);
    459         insertStructuredName(rawContactId1, "Johnh", "Smithh");
    460 
    461         long rawContactId2 = createRawContact(ACCOUNT_2);
    462         insertStructuredName(rawContactId2, "Johnh", "Smithh");
    463 
    464         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    465                 rawContactId1, rawContactId2);
    466 
    467         assertNotAggregated(rawContactId1, rawContactId2);
    468     }
    469 
    470     public void testAggregationExceptionKeepOutCheckUpdatesDisplayName() {
    471         long rawContactId1 = createRawContact(ACCOUNT_1);
    472         insertStructuredName(rawContactId1, "Johni", "Smithi");
    473 
    474         long rawContactId2 = createRawContact(ACCOUNT_2);
    475         insertStructuredName(rawContactId2, "Johnj", "Smithj");
    476 
    477         long rawContactId3 = createRawContact(ACCOUNT_3);
    478         insertStructuredName(rawContactId3, "Johnm", "Smithm");
    479 
    480         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    481                 rawContactId1, rawContactId2);
    482         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    483                 rawContactId1, rawContactId3);
    484         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    485                 rawContactId2, rawContactId3);
    486 
    487         assertAggregated(rawContactId1, rawContactId2, "Johnm Smithm");
    488         assertAggregated(rawContactId1, rawContactId3);
    489 
    490         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    491                 rawContactId1, rawContactId2);
    492         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    493                 rawContactId1, rawContactId3);
    494 
    495         assertNotAggregated(rawContactId1, rawContactId2);
    496         assertNotAggregated(rawContactId1, rawContactId3);
    497 
    498         String displayName1 = queryDisplayName(queryContactId(rawContactId1));
    499         assertEquals("Johni Smithi", displayName1);
    500 
    501         assertAggregated(rawContactId2, rawContactId3, "Johnm Smithm");
    502 
    503         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    504                 rawContactId2, rawContactId3);
    505         assertNotAggregated(rawContactId1, rawContactId2);
    506         assertNotAggregated(rawContactId1, rawContactId3);
    507         assertNotAggregated(rawContactId2, rawContactId3);
    508 
    509         String displayName2 = queryDisplayName(queryContactId(rawContactId1));
    510         assertEquals("Johni Smithi", displayName2);
    511 
    512         String displayName3 = queryDisplayName(queryContactId(rawContactId2));
    513         assertEquals("Johnj Smithj", displayName3);
    514 
    515         String displayName4 = queryDisplayName(queryContactId(rawContactId3));
    516         assertEquals("Johnm Smithm", displayName4);
    517     }
    518 
    519     public void testNonAggregationWithMultipleAffinities() {
    520         long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
    521         long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
    522         assertNotAggregated(rawContactId1, rawContactId2);
    523 
    524         // There are two aggregates this raw contact could join, so it should join neither
    525         long rawContactId3 = createRawContactWithName("John", "Doe", ACCOUNT_2);
    526         assertNotAggregated(rawContactId1, rawContactId3);
    527         assertNotAggregated(rawContactId2, rawContactId3);
    528 
    529         // Just in case - let's make sure the original two did not get aggregated in the process
    530         assertNotAggregated(rawContactId1, rawContactId2);
    531     }
    532 
    533     public void testSplitBecauseOfMultipleAffinities() {
    534         long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
    535         long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_2);
    536         assertAggregated(rawContactId1, rawContactId2);
    537 
    538         // The aggregate this raw contact could join has a raw contact from the same account,
    539         // let's not aggregate and break up the existing aggregate because of the ambiguity
    540         long rawContactId3 = createRawContactWithName("John", "Doe", ACCOUNT_1);
    541         assertNotAggregated(rawContactId1, rawContactId3);
    542         assertNotAggregated(rawContactId2, rawContactId3);
    543         assertNotAggregated(rawContactId1, rawContactId2);
    544     }
    545 
    546     public void testNonSplitBecauseOfMultipleAffinitiesWhenOverridden() {
    547         long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
    548         long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_2);
    549         long rawContactId3 = createRawContactWithName("John", "Doe", ACCOUNT_3);
    550         assertAggregated(rawContactId1, rawContactId2);
    551         assertAggregated(rawContactId1, rawContactId3);
    552         setAggregationException(
    553                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
    554         assertAggregated(rawContactId1, rawContactId2);
    555         assertAggregated(rawContactId1, rawContactId3);
    556 
    557         // The aggregate this raw contact could join has a raw contact from the same account,
    558         // let's not aggregate and break up the existing aggregate because of the ambiguity
    559         long rawContactId4 = createRawContactWithName("John", "Doe", ACCOUNT_1);
    560         assertAggregated(rawContactId1, rawContactId2);     // Aggregation exception
    561         assertNotAggregated(rawContactId1, rawContactId3);
    562         assertNotAggregated(rawContactId1, rawContactId4);
    563         assertNotAggregated(rawContactId3, rawContactId4);
    564     }
    565 
    566     public void testAggregationSuggestionsBasedOnName() {
    567         long rawContactId1 = createRawContact();
    568         insertStructuredName(rawContactId1, "Duane", null);
    569 
    570         // Exact name match
    571         long rawContactId2 = createRawContact();
    572         insertStructuredName(rawContactId2, "Duane", null);
    573         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    574                 rawContactId1, rawContactId2);
    575 
    576         // Edit distance == 0.84
    577         long rawContactId3 = createRawContact();
    578         insertStructuredName(rawContactId3, "Dwayne", null);
    579 
    580         // Edit distance == 0.6
    581         long rawContactId4 = createRawContact();
    582         insertStructuredName(rawContactId4, "Donny", null);
    583 
    584         long contactId1 = queryContactId(rawContactId1);
    585         long contactId2 = queryContactId(rawContactId2);
    586         long contactId3 = queryContactId(rawContactId3);
    587 
    588         assertSuggestions(contactId1, contactId2, contactId3);
    589     }
    590 
    591     public void testAggregationSuggestionsBasedOnPhoneNumber() {
    592 
    593         // Create two contacts that would not be aggregated because of name mismatch
    594         long rawContactId1 = createRawContact();
    595         insertStructuredName(rawContactId1, "Lord", "Farquaad");
    596         insertPhoneNumber(rawContactId1, "(888)555-1236");
    597 
    598         long rawContactId2 = createRawContact();
    599         insertStructuredName(rawContactId2, "Talking", "Donkey");
    600         insertPhoneNumber(rawContactId2, "1(888)555-1236");
    601 
    602         long contactId1 = queryContactId(rawContactId1);
    603         long contactId2 = queryContactId(rawContactId2);
    604         assertTrue(contactId1 != contactId2);
    605 
    606         assertSuggestions(contactId1, contactId2);
    607     }
    608 
    609     public void testAggregationSuggestionsBasedOnEmailAddress() {
    610 
    611         // Create two contacts that would not be aggregated because of name mismatch
    612         long rawContactId1 = createRawContact();
    613         insertStructuredName(rawContactId1, "Carl", "Fredricksen");
    614         insertEmail(rawContactId1, "up (at) android.com");
    615 
    616         long rawContactId2 = createRawContact();
    617         insertStructuredName(rawContactId2, "Charles", "Muntz");
    618         insertEmail(rawContactId2, "up (at) android.com");
    619 
    620         long contactId1 = queryContactId(rawContactId1);
    621         long contactId2 = queryContactId(rawContactId2);
    622         assertTrue(contactId1 != contactId2);
    623 
    624         assertSuggestions(contactId1, contactId2);
    625     }
    626 
    627     public void testAggregationSuggestionsBasedOnEmailAddressApproximateMatch() {
    628 
    629         // Create two contacts that would not be aggregated because of name mismatch
    630         long rawContactId1 = createRawContact();
    631         insertStructuredName(rawContactId1, "Bob", null);
    632         insertEmail(rawContactId1, "incredible (at) android.com");
    633 
    634         long rawContactId2 = createRawContact();
    635         insertStructuredName(rawContactId2, "Lucius", "Best");
    636         insertEmail(rawContactId2, "incrediball (at) android.com");
    637 
    638         long contactId1 = queryContactId(rawContactId1);
    639         long contactId2 = queryContactId(rawContactId2);
    640         assertTrue(contactId1 != contactId2);
    641 
    642         assertSuggestions(contactId1, contactId2);
    643     }
    644 
    645     public void testAggregationSuggestionsBasedOnNickname() {
    646         long rawContactId1 = createRawContact();
    647         insertStructuredName(rawContactId1, "Peter", "Parker");
    648         insertNickname(rawContactId1, "Spider-Man");
    649 
    650         long rawContactId2 = createRawContact();
    651         insertStructuredName(rawContactId2, "Manny", "Spider");
    652 
    653         long contactId1 = queryContactId(rawContactId1);
    654         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    655                 rawContactId1, rawContactId2);
    656 
    657         long contactId2 = queryContactId(rawContactId2);
    658         assertSuggestions(contactId1, contactId2);
    659     }
    660 
    661     public void testAggregationSuggestionsBasedOnNicknameMatchingName() {
    662         long rawContactId1 = createRawContact();
    663         insertStructuredName(rawContactId1, "Clark", "Kent");
    664         insertNickname(rawContactId1, "Superman");
    665 
    666         long rawContactId2 = createRawContact();
    667         insertStructuredName(rawContactId2, "Roy", "Williams");
    668         insertNickname(rawContactId2, "superman");
    669 
    670         long contactId1 = queryContactId(rawContactId1);
    671         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    672                 rawContactId1, rawContactId2);
    673 
    674         long contactId2 = queryContactId(rawContactId2);
    675         assertSuggestions(contactId1, contactId2);
    676     }
    677 
    678     public void testAggregationSuggestionsBasedOnCommonNickname() {
    679         long rawContactId1 = createRawContact();
    680         insertStructuredName(rawContactId1, "Dick", "Cherry");
    681 
    682         long rawContactId2 = createRawContact();
    683         insertStructuredName(rawContactId2, "Richard", "Cherry");
    684 
    685         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    686                 rawContactId1, rawContactId2);
    687 
    688         long contactId1 = queryContactId(rawContactId1);
    689         long contactId2 = queryContactId(rawContactId2);
    690         assertSuggestions(contactId1, contactId2);
    691     }
    692 
    693     public void testAggregationSuggestionsBasedOnPhoneNumberWithFilter() {
    694 
    695         // Create two contacts that would not be aggregated because of name mismatch
    696         long rawContactId1 = createRawContact();
    697         insertStructuredName(rawContactId1, "Lord", "Farquaad");
    698         insertPhoneNumber(rawContactId1, "(888)555-1236");
    699 
    700         long rawContactId2 = createRawContact();
    701         insertStructuredName(rawContactId2, "Talking", "Donkey");
    702         insertPhoneNumber(rawContactId2, "1(888)555-1236");
    703 
    704         long contactId1 = queryContactId(rawContactId1);
    705         long contactId2 = queryContactId(rawContactId2);
    706         assertTrue(contactId1 != contactId2);
    707 
    708         assertSuggestions(contactId1, "talk", contactId2);
    709         assertSuggestions(contactId1, "don", contactId2);
    710         assertSuggestions(contactId1, "", contactId2);
    711         assertSuggestions(contactId1, "eddie");
    712     }
    713 
    714     public void testChoosePhotoSetBeforeAggregation() {
    715         long rawContactId1 = createRawContact();
    716         setContactAccount(rawContactId1, "donut", "donut_act");
    717         insertPhoto(rawContactId1);
    718 
    719         long rawContactId2 = createRawContact();
    720         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
    721         long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2));
    722 
    723         long rawContactId3 = createRawContact();
    724         setContactAccount(rawContactId3, "froyo", "froyo_act");
    725         insertPhoto(rawContactId3);
    726 
    727         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    728                 rawContactId1, rawContactId2);
    729         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    730                 rawContactId1, rawContactId3);
    731         assertEquals(cupcakeId, queryPhotoId(queryContactId(rawContactId2)));
    732     }
    733 
    734     public void testChoosePhotoSetAfterAggregation() {
    735         long rawContactId1 = createRawContact();
    736         setContactAccount(rawContactId1, "donut", "donut_act");
    737         insertPhoto(rawContactId1);
    738 
    739         long rawContactId2 = createRawContact();
    740         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    741                 rawContactId1, rawContactId2);
    742         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
    743         long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2));
    744 
    745         long rawContactId3 = createRawContact();
    746         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    747                 rawContactId1, rawContactId3);
    748         setContactAccount(rawContactId3, "froyo", "froyo_act");
    749         insertPhoto(rawContactId3);
    750 
    751         assertEquals(cupcakeId, queryPhotoId(queryContactId(rawContactId2)));
    752     }
    753 
    754     public void testDisplayNameSources() {
    755         long rawContactId = createRawContact();
    756         long contactId = queryContactId(rawContactId);
    757 
    758         assertNull(queryDisplayName(contactId));
    759 
    760         insertEmail(rawContactId, "eclair (at) android.com");
    761         assertEquals("eclair (at) android.com", queryDisplayName(contactId));
    762 
    763         insertPhoneNumber(rawContactId, "800-555-5555");
    764         assertEquals("800-555-5555", queryDisplayName(contactId));
    765 
    766         ContentValues values = new ContentValues();
    767         values.put(Organization.COMPANY, "Android");
    768         insertOrganization(rawContactId, values);
    769         assertEquals("Android", queryDisplayName(contactId));
    770 
    771         insertNickname(rawContactId, "Dro");
    772         assertEquals("Dro", queryDisplayName(contactId));
    773 
    774         values.clear();
    775         values.put(StructuredName.GIVEN_NAME, "Eclair");
    776         values.put(StructuredName.FAMILY_NAME, "Android");
    777         insertStructuredName(rawContactId, values);
    778         assertEquals("Eclair Android", queryDisplayName(contactId));
    779     }
    780 
    781     public void testVerifiedName() {
    782         long rawContactId1 = createRawContactWithName("test1", "TEST1", ACCOUNT_1);
    783         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.NAME_VERIFIED, "1");
    784         long rawContactId2 = createRawContactWithName("test2", "TEST2", ACCOUNT_2);
    785         long rawContactId3 = createRawContactWithName("test3", "TEST3 LONG", ACCOUNT_3);
    786 
    787         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1,
    788                 rawContactId2);
    789         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1,
    790                 rawContactId3);
    791 
    792         long contactId = queryContactId(rawContactId1);
    793 
    794         // Should be the verified name
    795         assertEquals("test1 TEST1", queryDisplayName(contactId));
    796 
    797         // Mark a different name as verified - this should reset the NAME_VERIFIED field
    798         // for the other rawContacts
    799         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.NAME_VERIFIED, "1");
    800         assertStoredValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.NAME_VERIFIED, 0);
    801         assertEquals("test2 TEST2", queryDisplayName(contactId));
    802 
    803         // Reset the NAME_VERIFIED flag - now the most complex of the three names should win
    804         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.NAME_VERIFIED, "0");
    805         assertEquals("test3 TEST3 LONG", queryDisplayName(contactId));
    806     }
    807 
    808     public void testAggregationModeSuspendedSeparateTransactions() {
    809 
    810         // Setting aggregation mode to SUSPENDED should prevent aggregation from happening
    811         long rawContactId1 = createRawContact(ACCOUNT_1);
    812         storeValue(RawContacts.CONTENT_URI, rawContactId1,
    813                 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
    814         Uri name1 = insertStructuredName(rawContactId1, "THE", "SAME");
    815 
    816         long rawContactId2 = createRawContact(ACCOUNT_2);
    817         storeValue(RawContacts.CONTENT_URI, rawContactId2,
    818                 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
    819         insertStructuredName(rawContactId2, "THE", "SAME");
    820 
    821         assertNotAggregated(rawContactId1, rawContactId2);
    822 
    823         // Changing aggregation mode to DEFAULT should change nothing
    824         storeValue(RawContacts.CONTENT_URI, rawContactId1,
    825                 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT);
    826         storeValue(RawContacts.CONTENT_URI, rawContactId2,
    827                 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT);
    828         assertNotAggregated(rawContactId1, rawContactId2);
    829 
    830         // Changing the name should trigger aggregation
    831         storeValue(name1, StructuredName.GIVEN_NAME, "the");
    832         assertAggregated(rawContactId1, rawContactId2);
    833     }
    834 
    835     public void testAggregationModeInitializedAsSuspended() throws Exception {
    836 
    837         // Setting aggregation mode to SUSPENDED should prevent aggregation from happening
    838         ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
    839                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
    840                 .build();
    841         ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
    842                 .withValueBackReference(Data.RAW_CONTACT_ID, 0)
    843                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
    844                 .withValue(StructuredName.GIVEN_NAME, "John")
    845                 .withValue(StructuredName.FAMILY_NAME, "Doe")
    846                 .build();
    847         ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
    848                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
    849                 .build();
    850         ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
    851                 .withValueBackReference(Data.RAW_CONTACT_ID, 2)
    852                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
    853                 .withValue(StructuredName.GIVEN_NAME, "John")
    854                 .withValue(StructuredName.FAMILY_NAME, "Doe")
    855                 .build();
    856         ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
    857                 .withSelection(RawContacts._ID + "=?", new String[1])
    858                 .withSelectionBackReference(0, 0)
    859                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT)
    860                 .build();
    861         ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
    862                 .withSelection(RawContacts._ID + "=?", new String[1])
    863                 .withSelectionBackReference(0, 2)
    864                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT)
    865                 .build();
    866 
    867         ContentProviderResult[] results =
    868                 mResolver.applyBatch(ContactsContract.AUTHORITY,
    869                         Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6));
    870 
    871         long rawContactId1 = ContentUris.parseId(results[0].uri);
    872         long rawContactId2 = ContentUris.parseId(results[2].uri);
    873 
    874         assertNotAggregated(rawContactId1, rawContactId2);
    875     }
    876 
    877     public void testAggregationModeUpdatedToSuspended() throws Exception {
    878 
    879         // Setting aggregation mode to SUSPENDED should prevent aggregation from happening
    880         ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
    881                 .withValues(new ContentValues())
    882                 .build();
    883         ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
    884                 .withValueBackReference(Data.RAW_CONTACT_ID, 0)
    885                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
    886                 .withValue(StructuredName.GIVEN_NAME, "John")
    887                 .withValue(StructuredName.FAMILY_NAME, "Doe")
    888                 .build();
    889         ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
    890                 .withValues(new ContentValues())
    891                 .build();
    892         ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
    893                 .withValueBackReference(Data.RAW_CONTACT_ID, 2)
    894                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
    895                 .withValue(StructuredName.GIVEN_NAME, "John")
    896                 .withValue(StructuredName.FAMILY_NAME, "Doe")
    897                 .build();
    898         ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
    899                 .withSelection(RawContacts._ID + "=?", new String[1])
    900                 .withSelectionBackReference(0, 0)
    901                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
    902                 .build();
    903         ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
    904                 .withSelection(RawContacts._ID + "=?", new String[1])
    905                 .withSelectionBackReference(0, 2)
    906                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
    907                 .build();
    908 
    909         ContentProviderResult[] results =
    910                 mResolver.applyBatch(ContactsContract.AUTHORITY,
    911                         Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6));
    912 
    913         long rawContactId1 = ContentUris.parseId(results[0].uri);
    914         long rawContactId2 = ContentUris.parseId(results[2].uri);
    915 
    916         assertNotAggregated(rawContactId1, rawContactId2);
    917     }
    918 
    919     public void testAggregationModeSuspendedOverriddenByAggException() throws Exception {
    920         ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
    921                 .withValue(RawContacts.ACCOUNT_NAME, "a")
    922                 .withValue(RawContacts.ACCOUNT_TYPE, "b")
    923                 .build();
    924         ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
    925                 .withValueBackReference(Data.RAW_CONTACT_ID, 0)
    926                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
    927                 .withValue(StructuredName.GIVEN_NAME, "John")
    928                 .withValue(StructuredName.FAMILY_NAME, "Doe")
    929                 .build();
    930         ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
    931                 .withValue(RawContacts.ACCOUNT_NAME, "c")
    932                 .withValue(RawContacts.ACCOUNT_TYPE, "d")
    933                 .build();
    934         ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
    935                 .withValueBackReference(Data.RAW_CONTACT_ID, 2)
    936                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
    937                 .withValue(StructuredName.GIVEN_NAME, "John")
    938                 .withValue(StructuredName.FAMILY_NAME, "Doe")
    939                 .build();
    940         ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
    941                 .withSelection(RawContacts._ID + "=?", new String[1])
    942                 .withSelectionBackReference(0, 0)
    943                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
    944                 .build();
    945         ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
    946                 .withSelection(RawContacts._ID + "=?", new String[1])
    947                 .withSelectionBackReference(0, 2)
    948                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
    949                 .build();
    950 
    951         // Checking that aggregation mode SUSPENDED should be overridden by inserting
    952         // an explicit aggregation exception
    953         ContentProviderOperation cpo7 =
    954                 ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI)
    955                 .withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, 0)
    956                 .withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, 2)
    957                 .withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER)
    958                 .build();
    959 
    960         ContentProviderResult[] results =
    961                 mResolver.applyBatch(ContactsContract.AUTHORITY,
    962                         Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6, cpo7));
    963 
    964         long rawContactId1 = ContentUris.parseId(results[0].uri);
    965         long rawContactId2 = ContentUris.parseId(results[2].uri);
    966 
    967         assertAggregated(rawContactId1, rawContactId2);
    968     }
    969 
    970     private void assertSuggestions(long contactId, long... suggestions) {
    971         final Uri aggregateUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
    972         Uri uri = Uri.withAppendedPath(aggregateUri,
    973                 Contacts.AggregationSuggestions.CONTENT_DIRECTORY);
    974         assertSuggestions(uri, suggestions);
    975     }
    976 
    977     private void assertSuggestions(long contactId, String filter, long... suggestions) {
    978         final Uri aggregateUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
    979         Uri uri = Uri.withAppendedPath(Uri.withAppendedPath(aggregateUri,
    980                 Contacts.AggregationSuggestions.CONTENT_DIRECTORY), Uri.encode(filter));
    981         assertSuggestions(uri, suggestions);
    982     }
    983 
    984     private void assertSuggestions(Uri uri, long... suggestions) {
    985         final Cursor cursor = mResolver.query(uri,
    986                 new String[] { Contacts._ID, Contacts.CONTACT_PRESENCE },
    987                 null, null, null);
    988 
    989         assertEquals(suggestions.length, cursor.getCount());
    990 
    991         for (int i = 0; i < suggestions.length; i++) {
    992             cursor.moveToNext();
    993             assertEquals(suggestions[i], cursor.getLong(0));
    994         }
    995 
    996         cursor.close();
    997     }
    998 }
    999