Home | History | Annotate | Download | only in aggregation
      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.aggregation;
     18 
     19 import android.accounts.Account;
     20 import android.content.ContentProviderOperation;
     21 import android.content.ContentProviderResult;
     22 import android.content.ContentUris;
     23 import android.content.ContentValues;
     24 import android.database.Cursor;
     25 import android.net.Uri;
     26 import android.provider.ContactsContract;
     27 import android.provider.ContactsContract.AggregationExceptions;
     28 import android.provider.ContactsContract.CommonDataKinds.Organization;
     29 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
     30 import android.provider.ContactsContract.Contacts;
     31 import android.provider.ContactsContract.Contacts.AggregationSuggestions;
     32 import android.provider.ContactsContract.Contacts.Photo;
     33 import android.provider.ContactsContract.Data;
     34 import android.provider.ContactsContract.RawContacts;
     35 import android.provider.ContactsContract.StatusUpdates;
     36 import android.test.MoreAsserts;
     37 import android.test.suitebuilder.annotation.MediumTest;
     38 
     39 import com.android.providers.contacts.BaseContactsProvider2Test;
     40 import com.android.providers.contacts.TestUtils;
     41 import com.android.providers.contacts.tests.R;
     42 import com.android.providers.contacts.testutil.DataUtil;
     43 import com.android.providers.contacts.testutil.RawContactUtil;
     44 
     45 import com.google.android.collect.Lists;
     46 
     47 /**
     48  * Unit tests for {@link ContactAggregator}.
     49  *
     50  * Run the test like this:
     51  * <code>
     52  * adb shell am instrument -e class com.android.providers.contacts.ContactAggregatorTest -w \
     53  *         com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
     54  * </code>
     55  */
     56 @MediumTest
     57 public class ContactAggregatorTest extends BaseContactsProvider2Test {
     58 
     59     private static final Account ACCOUNT_1 = new Account("account_name_1", "account_type_1");
     60     private static final Account ACCOUNT_2 = new Account("account_name_2", "account_type_2");
     61     private static final Account ACCOUNT_3 = new Account("account_name_3", "account_type_3");
     62 
     63     private static final String[] AGGREGATION_EXCEPTION_PROJECTION = new String[] {
     64             AggregationExceptions.TYPE,
     65             AggregationExceptions.RAW_CONTACT_ID1,
     66             AggregationExceptions.RAW_CONTACT_ID2
     67     };
     68 
     69     public void testCrudAggregationExceptions() throws Exception {
     70         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "zz", "top");
     71         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "aa", "bottom");
     72 
     73         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
     74                 rawContactId1, rawContactId2);
     75 
     76         String selection = "(" + AggregationExceptions.RAW_CONTACT_ID1 + "=" + rawContactId1
     77                 + " AND " + AggregationExceptions.RAW_CONTACT_ID2 + "=" + rawContactId2
     78                 + ") OR (" + AggregationExceptions.RAW_CONTACT_ID1 + "=" + rawContactId2
     79                 + " AND " + AggregationExceptions.RAW_CONTACT_ID2 + "=" + rawContactId1 + ")";
     80 
     81         // Refetch the row we have just inserted
     82         Cursor c = mResolver.query(AggregationExceptions.CONTENT_URI,
     83                 AGGREGATION_EXCEPTION_PROJECTION, selection, null, null);
     84 
     85         assertTrue(c.moveToFirst());
     86         assertEquals(AggregationExceptions.TYPE_KEEP_TOGETHER, c.getInt(0));
     87         assertTrue((rawContactId1 == c.getLong(1) && rawContactId2 == c.getLong(2))
     88                 || (rawContactId2 == c.getLong(1) && rawContactId1 == c.getLong(2)));
     89         assertFalse(c.moveToNext());
     90         c.close();
     91 
     92         // Change from TYPE_KEEP_IN to TYPE_KEEP_OUT
     93         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
     94                 rawContactId1, rawContactId2);
     95 
     96         c = mResolver.query(AggregationExceptions.CONTENT_URI, AGGREGATION_EXCEPTION_PROJECTION,
     97                 selection, null, null);
     98 
     99         assertTrue(c.moveToFirst());
    100         assertEquals(AggregationExceptions.TYPE_KEEP_SEPARATE, c.getInt(0));
    101         assertTrue((rawContactId1 == c.getLong(1) && rawContactId2 == c.getLong(2))
    102                 || (rawContactId2 == c.getLong(1) && rawContactId1 == c.getLong(2)));
    103         assertFalse(c.moveToNext());
    104         c.close();
    105 
    106         // Delete the rule
    107         setAggregationException(AggregationExceptions.TYPE_AUTOMATIC,
    108                 rawContactId1, rawContactId2);
    109 
    110         // Verify that the row is gone
    111         c = mResolver.query(AggregationExceptions.CONTENT_URI, AGGREGATION_EXCEPTION_PROJECTION,
    112                 selection, null, null);
    113         assertFalse(c.moveToFirst());
    114         c.close();
    115     }
    116 
    117     public void testAggregationCreatesNewAggregate() {
    118         long rawContactId = RawContactUtil.createRawContact(mResolver);
    119 
    120         Uri resultUri = DataUtil.insertStructuredName(mResolver, rawContactId, "Johna", "Smitha");
    121 
    122         // Parse the URI and confirm that it contains an ID
    123         assertTrue(ContentUris.parseId(resultUri) != 0);
    124 
    125         long contactId = queryContactId(rawContactId);
    126         assertTrue(contactId != 0);
    127 
    128         String displayName = queryDisplayName(contactId);
    129         assertEquals("Johna Smitha", displayName);
    130     }
    131 
    132     public void testAggregationOfExactFullNameMatch() {
    133         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    134         DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnb", "Smithb");
    135 
    136         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    137         DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnb", "Smithb");
    138 
    139         assertAggregated(rawContactId1, rawContactId2, "Johnb Smithb");
    140     }
    141 
    142     public void testAggregationIgnoresInvisibleContact() {
    143         Account account = new Account("accountName", "accountType");
    144         createAutoAddGroup(account);
    145 
    146         long rawContactId1 = RawContactUtil.createRawContact(mResolver, account);
    147         DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder");
    148 
    149         // Hide by removing from all groups
    150         removeGroupMemberships(rawContactId1);
    151 
    152         long rawContactId2 = RawContactUtil.createRawContact(mResolver, account);
    153         DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder");
    154 
    155         long rawContactId3 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    156         DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder");
    157 
    158         assertNotAggregated(rawContactId1, rawContactId2);
    159         assertNotAggregated(rawContactId1, rawContactId3);
    160         assertAggregated(rawContactId2, rawContactId3, "Flynn Ryder");
    161     }
    162 
    163     public void testAggregationOfCaseInsensitiveFullNameMatch() {
    164         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    165         DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnc", "Smithc");
    166 
    167         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    168         DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnc", "smithc");
    169 
    170         assertAggregated(rawContactId1, rawContactId2, "Johnc Smithc");
    171     }
    172 
    173     public void testAggregationOfLastNameMatch() {
    174         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    175         DataUtil.insertStructuredName(mResolver, rawContactId1, null, "Johnd");
    176 
    177         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    178         DataUtil.insertStructuredName(mResolver, rawContactId2, null, "johnd");
    179 
    180         assertAggregated(rawContactId1, rawContactId2, "Johnd");
    181     }
    182 
    183     public void testNonAggregationOfFirstNameMatch() {
    184         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    185         DataUtil.insertStructuredName(mResolver, rawContactId1, "Johne", "Smithe");
    186 
    187         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    188         DataUtil.insertStructuredName(mResolver, rawContactId2, "Johne", null);
    189 
    190         assertNotAggregated(rawContactId1, rawContactId2);
    191     }
    192 
    193     public void testNonAggregationOfLastNameMatch() {
    194         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    195         DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnf", "Smithf");
    196 
    197         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    198         DataUtil.insertStructuredName(mResolver, rawContactId2, null, "Smithf");
    199 
    200         assertNotAggregated(rawContactId1, rawContactId2);
    201     }
    202 
    203     public void testAggregationOfConcatenatedFullNameMatch() {
    204         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    205         DataUtil.insertStructuredName(mResolver, rawContactId1, "Johng", "Smithg");
    206 
    207         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    208         DataUtil.insertStructuredName(mResolver, rawContactId2, "johngsmithg", null);
    209 
    210         assertAggregated(rawContactId1, rawContactId2, "Johng Smithg");
    211     }
    212 
    213     public void testAggregationOfNormalizedFullNameMatch() {
    214         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    215         DataUtil.insertStructuredName(mResolver, rawContactId1, "H\u00e9l\u00e8ne", "Bj\u00f8rn");
    216 
    217         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    218         DataUtil.insertStructuredName(mResolver, rawContactId2, "helene bjorn", null);
    219 
    220         assertAggregated(rawContactId1, rawContactId2, "H\u00e9l\u00e8ne Bj\u00f8rn");
    221     }
    222 
    223     public void testAggregationOfNormalizedFullNameMatchWithReadOnlyAccount() {
    224         long rawContactId1 = RawContactUtil.createRawContact(mResolver, new Account("acct",
    225                 READ_ONLY_ACCOUNT_TYPE));
    226         DataUtil.insertStructuredName(mResolver, rawContactId1, "H\u00e9l\u00e8ne", "Bj\u00f8rn");
    227 
    228         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
    229         DataUtil.insertStructuredName(mResolver, rawContactId2, "helene bjorn", null);
    230 
    231         assertAggregated(rawContactId1, rawContactId2, "helene bjorn");
    232     }
    233 
    234     public void testAggregationOfNumericNames() {
    235         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    236         DataUtil.insertStructuredName(mResolver, rawContactId1, "123", null);
    237 
    238         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    239         DataUtil.insertStructuredName(mResolver, rawContactId2, "1-2-3", null);
    240 
    241         assertAggregated(rawContactId1, rawContactId2, "1-2-3");
    242     }
    243 
    244     public void testAggregationOfInconsistentlyParsedNames() {
    245         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    246 
    247         ContentValues values = new ContentValues();
    248         values.put(StructuredName.DISPLAY_NAME, "604 Arizona Ave");
    249         values.put(StructuredName.GIVEN_NAME, "604");
    250         values.put(StructuredName.MIDDLE_NAME, "Arizona");
    251         values.put(StructuredName.FAMILY_NAME, "Ave");
    252         DataUtil.insertStructuredName(mResolver, rawContactId1, values);
    253 
    254         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    255         values.clear();
    256         values.put(StructuredName.DISPLAY_NAME, "604 Arizona Ave");
    257         values.put(StructuredName.GIVEN_NAME, "604");
    258         values.put(StructuredName.FAMILY_NAME, "Arizona Ave");
    259         DataUtil.insertStructuredName(mResolver, rawContactId2, values);
    260 
    261         assertAggregated(rawContactId1, rawContactId2, "604 Arizona Ave");
    262     }
    263 
    264     public void testAggregationBasedOnMiddleName() {
    265         ContentValues values = new ContentValues();
    266         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    267         values.put(StructuredName.GIVEN_NAME, "John");
    268         values.put(StructuredName.GIVEN_NAME, "Abigale");
    269         values.put(StructuredName.FAMILY_NAME, "James");
    270 
    271         DataUtil.insertStructuredName(mResolver, rawContactId1, values);
    272 
    273         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    274         values.clear();
    275         values.put(StructuredName.GIVEN_NAME, "John");
    276         values.put(StructuredName.GIVEN_NAME, "Marie");
    277         values.put(StructuredName.FAMILY_NAME, "James");
    278         DataUtil.insertStructuredName(mResolver, rawContactId2, values);
    279 
    280         assertNotAggregated(rawContactId1, rawContactId2);
    281     }
    282 
    283     public void testAggregationBasedOnPhoneNumberNoNameData() {
    284         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    285         insertPhoneNumber(rawContactId1, "(888)555-1231");
    286 
    287         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    288         insertPhoneNumber(rawContactId2, "1(888)555-1231");
    289 
    290         assertAggregated(rawContactId1, rawContactId2);
    291     }
    292 
    293     public void testAggregationBasedOnPhoneNumberWhenTargetAggregateHasNoName() {
    294         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    295         insertPhoneNumber(rawContactId1, "(888)555-1232");
    296 
    297         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    298         DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnl", "Smithl");
    299         insertPhoneNumber(rawContactId2, "1(888)555-1232");
    300 
    301         assertAggregated(rawContactId1, rawContactId2);
    302     }
    303 
    304     public void testAggregationBasedOnPhoneNumberWhenNewContactHasNoName() {
    305         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    306         DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnm", "Smithm");
    307         insertPhoneNumber(rawContactId1, "(888)555-1233");
    308 
    309         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    310         insertPhoneNumber(rawContactId2, "1(888)555-1233");
    311 
    312         assertAggregated(rawContactId1, rawContactId2);
    313     }
    314 
    315     public void testAggregationBasedOnPhoneNumberWithDifferentNames() {
    316         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    317         DataUtil.insertStructuredName(mResolver, rawContactId1, "Baby", "Bear");
    318         insertPhoneNumber(rawContactId1, "(888)555-1235");
    319 
    320         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    321         DataUtil.insertStructuredName(mResolver, rawContactId2, "Blind", "Mouse");
    322         insertPhoneNumber(rawContactId2, "1(888)555-1235");
    323 
    324         assertNotAggregated(rawContactId1, rawContactId2);
    325     }
    326 
    327     public void testAggregationBasedOnPhoneNumberWithJustFirstName() {
    328         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    329         DataUtil.insertStructuredName(mResolver, rawContactId1, "Chick", "Notnull");
    330         insertPhoneNumber(rawContactId1, "(888)555-1236");
    331 
    332         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    333         DataUtil.insertStructuredName(mResolver, rawContactId2, "Chick", null);
    334         insertPhoneNumber(rawContactId2, "1(888)555-1236");
    335 
    336         assertAggregated(rawContactId1, rawContactId2);
    337     }
    338 
    339     public void testAggregationBasedOnEmailNoNameData() {
    340         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    341         insertEmail(rawContactId1, "lightning (at) android.com");
    342 
    343         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    344         insertEmail(rawContactId2, "lightning (at) android.com");
    345 
    346         assertAggregated(rawContactId1, rawContactId2);
    347     }
    348 
    349     public void testAggregationBasedOnEmailWhenTargetAggregateHasNoName() {
    350         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    351         insertEmail(rawContactId1, "mcqueen (at) android.com");
    352 
    353         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    354         DataUtil.insertStructuredName(mResolver, rawContactId2, "Lightning", "McQueen");
    355         insertEmail(rawContactId2, "mcqueen (at) android.com");
    356 
    357         assertAggregated(rawContactId1, rawContactId2, "Lightning McQueen");
    358     }
    359 
    360     public void testAggregationBasedOnEmailWhenNewContactHasNoName() {
    361         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    362         DataUtil.insertStructuredName(mResolver, rawContactId1, "Doc", "Hudson");
    363         insertEmail(rawContactId1, "doc (at) android.com");
    364 
    365         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    366         insertEmail(rawContactId2, "doc (at) android.com");
    367 
    368         assertAggregated(rawContactId1, rawContactId2);
    369     }
    370 
    371     public void testAggregationBasedOnEmailWithDifferentNames() {
    372         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    373         DataUtil.insertStructuredName(mResolver, rawContactId1, "Chick", "Hicks");
    374         insertEmail(rawContactId1, "hicky (at) android.com");
    375 
    376         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    377         DataUtil.insertStructuredName(mResolver, rawContactId2, "Luigi", "Guido");
    378         insertEmail(rawContactId2, "hicky (at) android.com");
    379 
    380         assertNotAggregated(rawContactId1, rawContactId2);
    381     }
    382 
    383     public void testAggregationByCommonNicknameWithLastName() {
    384         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    385         DataUtil.insertStructuredName(mResolver, rawContactId1, "Bill", "Gore");
    386 
    387         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    388         DataUtil.insertStructuredName(mResolver, rawContactId2, "William", "Gore");
    389 
    390         assertAggregated(rawContactId1, rawContactId2, "William Gore");
    391     }
    392 
    393     public void testAggregationByCommonNicknameOnly() {
    394         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    395         DataUtil.insertStructuredName(mResolver, rawContactId1, "Lawrence", null);
    396 
    397         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    398         DataUtil.insertStructuredName(mResolver, rawContactId2, "Larry", null);
    399 
    400         assertAggregated(rawContactId1, rawContactId2, "Lawrence");
    401     }
    402 
    403     public void testAggregationByNicknameNoStructuredName() {
    404         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    405         insertNickname(rawContactId1, "Frozone");
    406 
    407         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    408         insertNickname(rawContactId2, "Frozone");
    409 
    410         assertAggregated(rawContactId1, rawContactId2);
    411     }
    412 
    413     public void testAggregationByNicknameWithDifferentNames() {
    414         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    415         DataUtil.insertStructuredName(mResolver, rawContactId1, "Helen", "Parr");
    416         insertNickname(rawContactId1, "Elastigirl");
    417 
    418         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    419         DataUtil.insertStructuredName(mResolver, rawContactId2, "Shawn", "Johnson");
    420         insertNickname(rawContactId2, "Elastigirl");
    421 
    422         assertNotAggregated(rawContactId1, rawContactId2);
    423     }
    424 
    425     public void testNonAggregationOnOrganization() {
    426         ContentValues values = new ContentValues();
    427         values.put(Organization.TITLE, "Monsters, Inc");
    428         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    429         insertOrganization(rawContactId1, values);
    430         insertNickname(rawContactId1, "Boo");
    431 
    432         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    433         insertOrganization(rawContactId2, values);
    434         insertNickname(rawContactId2, "Rendall");   // To force reaggregation
    435 
    436         assertNotAggregated(rawContactId1, rawContactId2);
    437     }
    438 
    439     public void testAggregationByIdentity() {
    440         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    441         insertIdentity(rawContactId1, "iden1", "namespace1");
    442 
    443         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    444         insertIdentity(rawContactId2, "iden1", "namespace1");
    445 
    446         assertAggregated(rawContactId1, rawContactId2);
    447     }
    448 
    449     public void testAggregationExceptionKeepIn() {
    450         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    451         DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnk", "Smithk");
    452 
    453         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    454         DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnkx", "Smithkx");
    455 
    456         long contactId1 = queryContactId(rawContactId1);
    457         long contactId2 = queryContactId(rawContactId2);
    458 
    459         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    460                 rawContactId1, rawContactId2);
    461 
    462         assertAggregated(rawContactId1, rawContactId2, "Johnkx Smithkx");
    463 
    464         // Assert that the empty aggregate got removed
    465         long newContactId1 = queryContactId(rawContactId1);
    466         if (contactId1 != newContactId1) {
    467             Cursor cursor = queryContact(contactId1);
    468             assertFalse(cursor.moveToFirst());
    469             cursor.close();
    470         } else {
    471             Cursor cursor = queryContact(contactId2);
    472             assertFalse(cursor.moveToFirst());
    473             cursor.close();
    474         }
    475     }
    476 
    477     public void testAggregationExceptionKeepOut() {
    478         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    479         DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnh", "Smithh");
    480 
    481         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    482         DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnh", "Smithh");
    483 
    484         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    485                 rawContactId1, rawContactId2);
    486 
    487         assertNotAggregated(rawContactId1, rawContactId2);
    488     }
    489 
    490     public void testAggregationExceptionKeepOutCheckUpdatesDisplayName() {
    491         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    492         DataUtil.insertStructuredName(mResolver, rawContactId1, "Johni", "Smithi");
    493 
    494         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    495         DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnj", "Smithj");
    496 
    497         long rawContactId3 = RawContactUtil.createRawContact(mResolver, ACCOUNT_3);
    498         DataUtil.insertStructuredName(mResolver, rawContactId3, "Johnm", "Smithm");
    499 
    500         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    501                 rawContactId1, rawContactId2);
    502         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    503                 rawContactId1, rawContactId3);
    504         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    505                 rawContactId2, rawContactId3);
    506 
    507         assertAggregated(rawContactId1, rawContactId2, "Johnm Smithm");
    508         assertAggregated(rawContactId1, rawContactId3);
    509 
    510         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    511                 rawContactId1, rawContactId2);
    512         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    513                 rawContactId1, rawContactId3);
    514 
    515         assertNotAggregated(rawContactId1, rawContactId2);
    516         assertNotAggregated(rawContactId1, rawContactId3);
    517 
    518         String displayName1 = queryDisplayName(queryContactId(rawContactId1));
    519         assertEquals("Johni Smithi", displayName1);
    520 
    521         assertAggregated(rawContactId2, rawContactId3, "Johnm Smithm");
    522 
    523         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    524                 rawContactId2, rawContactId3);
    525         assertNotAggregated(rawContactId1, rawContactId2);
    526         assertNotAggregated(rawContactId1, rawContactId3);
    527         assertNotAggregated(rawContactId2, rawContactId3);
    528 
    529         String displayName2 = queryDisplayName(queryContactId(rawContactId1));
    530         assertEquals("Johni Smithi", displayName2);
    531 
    532         String displayName3 = queryDisplayName(queryContactId(rawContactId2));
    533         assertEquals("Johnj Smithj", displayName3);
    534 
    535         String displayName4 = queryDisplayName(queryContactId(rawContactId3));
    536         assertEquals("Johnm Smithm", displayName4);
    537     }
    538 
    539     public void testAggregationExceptionKeepOutCheckResultDisplayNames() {
    540         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "c", "c", ACCOUNT_1);
    541         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "b", "b", ACCOUNT_2);
    542         long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "a", "a", ACCOUNT_3);
    543 
    544         // Join all contacts
    545         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    546                 rawContactId1, rawContactId2);
    547         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    548                 rawContactId1, rawContactId3);
    549         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
    550                 rawContactId2, rawContactId3);
    551 
    552         // Separate all contacts. The order (2-3 , 1-2, 1-3) is important
    553         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    554                 rawContactId2, rawContactId3);
    555         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    556                 rawContactId1, rawContactId2);
    557         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    558                 rawContactId1, rawContactId3);
    559 
    560         // Verify that we have three different contacts
    561         long contactId1 = queryContactId(rawContactId1);
    562         long contactId2 = queryContactId(rawContactId2);
    563         long contactId3 = queryContactId(rawContactId3);
    564 
    565         assertTrue(contactId1 != contactId2);
    566         assertTrue(contactId1 != contactId3);
    567         assertTrue(contactId2 != contactId3);
    568 
    569         // Verify that each raw contact contribute to the contact display name
    570         assertDisplayNameEquals(contactId1, rawContactId1);
    571         assertDisplayNameEquals(contactId2, rawContactId2);
    572         assertDisplayNameEquals(contactId3, rawContactId3);
    573     }
    574 
    575     public void testNonAggregationWithMultipleAffinities() {
    576         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    577                 ACCOUNT_1);
    578         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    579                 ACCOUNT_1);
    580         assertNotAggregated(rawContactId1, rawContactId2);
    581 
    582         // There are two aggregates this raw contact could join, so it should join neither
    583         long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    584                 ACCOUNT_2);
    585         assertNotAggregated(rawContactId1, rawContactId3);
    586         assertNotAggregated(rawContactId2, rawContactId3);
    587 
    588         // Just in case - let's make sure the original two did not get aggregated in the process
    589         assertNotAggregated(rawContactId1, rawContactId2);
    590     }
    591 
    592     public void testSplitBecauseOfMultipleAffinities() {
    593         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    594                 ACCOUNT_1);
    595         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    596                 ACCOUNT_2);
    597         assertAggregated(rawContactId1, rawContactId2);
    598 
    599         // The aggregate this raw contact could join has a raw contact from the same account,
    600         // let's not aggregate and break up the existing aggregate because of the ambiguity
    601         long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    602                 ACCOUNT_1);
    603         assertNotAggregated(rawContactId1, rawContactId3);
    604         assertNotAggregated(rawContactId2, rawContactId3);
    605         assertNotAggregated(rawContactId1, rawContactId2);
    606     }
    607 
    608     public void testAggregation_notAggregateByPhoneticName() {
    609         // Different names, but have the same phonetic name.  Shouldn't be aggregated.
    610 
    611         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    612         DataUtil.insertStructuredName(mResolver, rawContactId1, "Sergey", null, "Yamada");
    613 
    614         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    615         DataUtil.insertStructuredName(mResolver, rawContactId2, "Lawrence", null, "Yamada");
    616 
    617         assertNotAggregated(rawContactId1, rawContactId2);
    618     }
    619 
    620     public void testAggregation_notAggregateByPhoneticName_2() {
    621         // Have the same phonetic name.  One has a regular name too.  Shouldn't be aggregated.
    622 
    623         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    624         DataUtil.insertStructuredName(mResolver, rawContactId1, null, null, "Yamada");
    625 
    626         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    627         DataUtil.insertStructuredName(mResolver, rawContactId2, "Lawrence", null, "Yamada");
    628 
    629         assertNotAggregated(rawContactId1, rawContactId2);
    630     }
    631 
    632     public void testAggregation_PhoneticNameOnly() {
    633         // If a contact has no name but a phonetic name, then its display will be set from the
    634         // phonetic name.  In this case, we still aggregate by the display name.
    635 
    636         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
    637         DataUtil.insertStructuredName(mResolver, rawContactId1, null, null, "Yamada");
    638 
    639         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    640         DataUtil.insertStructuredName(mResolver, rawContactId2, null, null, "Yamada");
    641 
    642         assertAggregated(rawContactId1, rawContactId2, "Yamada");
    643     }
    644 
    645     public void testReaggregationWhenBecomesInvisible() {
    646         Account account = new Account("accountName", "accountType");
    647         createAutoAddGroup(account);
    648 
    649         long rawContactId1 = RawContactUtil.createRawContact(mResolver, account);
    650         DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder");
    651 
    652         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    653         DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder");
    654 
    655         long rawContactId3 = RawContactUtil.createRawContact(mResolver, account);
    656         DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder");
    657 
    658         assertNotAggregated(rawContactId1, rawContactId3);
    659         assertNotAggregated(rawContactId2, rawContactId3);
    660         assertNotAggregated(rawContactId1, rawContactId2);
    661 
    662         // Hide by removing from all groups
    663         removeGroupMemberships(rawContactId3);
    664 
    665         assertAggregated(rawContactId1, rawContactId2, "Flynn Ryder");
    666         assertNotAggregated(rawContactId1, rawContactId3);
    667         assertNotAggregated(rawContactId2, rawContactId3);
    668     }
    669 
    670     public void testReaggregationWhenBecomesInvisibleSecondaryDataMatch() {
    671         Account account = new Account("accountName", "accountType");
    672         createAutoAddGroup(account);
    673 
    674         long rawContactId1 = RawContactUtil.createRawContact(mResolver, account);
    675         DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder");
    676         insertPhoneNumber(rawContactId1, "1234567890");
    677 
    678         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    679         insertPhoneNumber(rawContactId2, "1234567890");
    680 
    681         long rawContactId3 = RawContactUtil.createRawContact(mResolver, account);
    682         DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder");
    683 
    684         assertNotAggregated(rawContactId1, rawContactId3);
    685         assertNotAggregated(rawContactId2, rawContactId3);
    686         assertNotAggregated(rawContactId1, rawContactId2);
    687 
    688         // Hide by removing from all groups
    689         removeGroupMemberships(rawContactId3);
    690 
    691         assertAggregated(rawContactId1, rawContactId2, "Flynn Ryder");
    692         assertNotAggregated(rawContactId1, rawContactId3);
    693         assertNotAggregated(rawContactId2, rawContactId3);
    694     }
    695 
    696     public void testReaggregationWhenBecomesVisible() {
    697         Account account = new Account("accountName", "accountType");
    698         long groupId = createAutoAddGroup(account);
    699 
    700         long rawContactId1 = RawContactUtil.createRawContact(mResolver, account);
    701         DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder");
    702 
    703         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
    704         DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder");
    705 
    706         long rawContactId3 = RawContactUtil.createRawContact(mResolver, account);
    707         removeGroupMemberships(rawContactId3);
    708         DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder");
    709 
    710         assertAggregated(rawContactId1, rawContactId2, "Flynn Ryder");
    711         assertNotAggregated(rawContactId1, rawContactId3);
    712         assertNotAggregated(rawContactId2, rawContactId3);
    713 
    714         insertGroupMembership(rawContactId3, groupId);
    715 
    716         assertNotAggregated(rawContactId1, rawContactId3);
    717         assertNotAggregated(rawContactId2, rawContactId3);
    718         assertNotAggregated(rawContactId1, rawContactId2);
    719     }
    720 
    721     public void testNonSplitBecauseOfMultipleAffinitiesWhenOverridden() {
    722         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    723                 ACCOUNT_1);
    724         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    725                 ACCOUNT_2);
    726         long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    727                 ACCOUNT_3);
    728         assertAggregated(rawContactId1, rawContactId2);
    729         assertAggregated(rawContactId1, rawContactId3);
    730         setAggregationException(
    731                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
    732         assertAggregated(rawContactId1, rawContactId2);
    733         assertAggregated(rawContactId1, rawContactId3);
    734 
    735         // The aggregate this raw contact could join has a raw contact from the same account,
    736         // let's not aggregate and break up the existing aggregate because of the ambiguity
    737         long rawContactId4 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    738                 ACCOUNT_1);
    739         assertAggregated(rawContactId1, rawContactId2);     // Aggregation exception
    740         assertNotAggregated(rawContactId1, rawContactId3);
    741         assertNotAggregated(rawContactId1, rawContactId4);
    742         assertNotAggregated(rawContactId3, rawContactId4);
    743     }
    744 
    745     public void testNonAggregationFromSameAccount() {
    746         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    747                 ACCOUNT_1);
    748         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    749                 ACCOUNT_1);
    750         assertNotAggregated(rawContactId1, rawContactId2);
    751     }
    752 
    753     public void testNonAggregationFromSameAccountNoCommonData() {
    754         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    755                 ACCOUNT_1);
    756         insertEmail(rawContactId1, "lightning1 (at) android.com");
    757         insertPhoneNumber(rawContactId1, "111-222-3333");
    758         insertIdentity(rawContactId1, "iden1", "namespace");
    759 
    760         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    761                 ACCOUNT_1);
    762         insertEmail(rawContactId2, "lightning2 (at) android.com");
    763         insertPhoneNumber(rawContactId2, "555-666-7777");
    764         insertIdentity(rawContactId1, "iden2", "namespace");
    765 
    766         assertNotAggregated(rawContactId1, rawContactId2);
    767     }
    768 
    769     public void testAggregationFromSameAccountEmailSame() {
    770         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    771                 ACCOUNT_1);
    772         insertEmail(rawContactId1, "lightning (at) android.com");
    773 
    774         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    775                 ACCOUNT_1);
    776         insertEmail(rawContactId2, "lightning (at) android.com");
    777 
    778         assertAggregated(rawContactId1, rawContactId2);
    779     }
    780 
    781     public void testNonAggregationFromSameAccountEmailDifferent() {
    782         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    783                 ACCOUNT_1);
    784         insertEmail(rawContactId1, "lightning1 (at) android.com");
    785 
    786         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    787                 ACCOUNT_1);
    788         insertEmail(rawContactId2, "lightning2 (at) android.com");
    789         insertEmail(rawContactId2, "lightning3 (at) android.com");
    790 
    791         assertNotAggregated(rawContactId1, rawContactId2);
    792     }
    793 
    794     public void testAggregationFromSameAccountIdentitySame() {
    795         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    796                 ACCOUNT_1);
    797         insertIdentity(rawContactId1, "iden", "namespace");
    798 
    799         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    800                 ACCOUNT_1);
    801         insertIdentity(rawContactId2, "iden", "namespace");
    802 
    803         assertAggregated(rawContactId1, rawContactId2);
    804     }
    805 
    806     public void testNonAggregationFromSameAccountIdentityDifferent() {
    807         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    808                 ACCOUNT_1);
    809         insertIdentity(rawContactId1, "iden1", "namespace1");
    810         insertIdentity(rawContactId1, "iden2", "namespace2");
    811 
    812         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    813                 ACCOUNT_1);
    814         insertIdentity(rawContactId2, "iden2", "namespace1");
    815         insertIdentity(rawContactId2, "iden1", "namespace2");
    816 
    817         assertNotAggregated(rawContactId1, rawContactId2);
    818     }
    819 
    820     public void testAggregationFromSameAccountPhoneNumberSame() {
    821         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    822                 ACCOUNT_1);
    823         insertPhoneNumber(rawContactId1, "111-222-3333");
    824 
    825         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    826                 ACCOUNT_1);
    827         insertPhoneNumber(rawContactId2, "111-222-3333");
    828 
    829         assertAggregated(rawContactId1, rawContactId2);
    830     }
    831 
    832     public void testAggregationFromSameAccountPhoneNumberNormalizedSame() {
    833         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    834                 ACCOUNT_1);
    835         insertPhoneNumber(rawContactId1, "111-222-3333");
    836 
    837         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    838                 ACCOUNT_1);
    839         insertPhoneNumber(rawContactId2, "+1-111-222-3333");
    840 
    841         assertAggregated(rawContactId1, rawContactId2);
    842     }
    843 
    844     public void testNonAggregationFromSameAccountPhoneNumberDifferent() {
    845         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    846                 ACCOUNT_1);
    847         insertPhoneNumber(rawContactId1, "111-222-3333");
    848 
    849         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
    850                 ACCOUNT_1);
    851         insertPhoneNumber(rawContactId2, "111-222-3334");
    852 
    853         assertNotAggregated(rawContactId1, rawContactId2);
    854     }
    855 
    856     public void testAggregationSuggestionsBasedOnName() {
    857         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
    858         DataUtil.insertStructuredName(mResolver, rawContactId1, "Duane", null);
    859 
    860         // Exact name match
    861         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
    862         DataUtil.insertStructuredName(mResolver, rawContactId2, "Duane", null);
    863         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    864                 rawContactId1, rawContactId2);
    865 
    866         // Edit distance == 0.84
    867         long rawContactId3 = RawContactUtil.createRawContact(mResolver);
    868         DataUtil.insertStructuredName(mResolver, rawContactId3, "Dwayne", null);
    869 
    870         // Edit distance == 0.6
    871         long rawContactId4 = RawContactUtil.createRawContact(mResolver);
    872         DataUtil.insertStructuredName(mResolver, rawContactId4, "Donny", null);
    873 
    874         long contactId1 = queryContactId(rawContactId1);
    875         long contactId2 = queryContactId(rawContactId2);
    876         long contactId3 = queryContactId(rawContactId3);
    877 
    878         assertSuggestions(contactId1, contactId2, contactId3);
    879     }
    880 
    881     public void testAggregationSuggestionsBasedOnPhoneNumber() {
    882 
    883         // Create two contacts that would not be aggregated because of name mismatch
    884         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
    885         DataUtil.insertStructuredName(mResolver, rawContactId1, "Lord", "Farquaad");
    886         insertPhoneNumber(rawContactId1, "(888)555-1236");
    887 
    888         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
    889         DataUtil.insertStructuredName(mResolver, rawContactId2, "Talking", "Donkey");
    890         insertPhoneNumber(rawContactId2, "1(888)555-1236");
    891 
    892         long contactId1 = queryContactId(rawContactId1);
    893         long contactId2 = queryContactId(rawContactId2);
    894         assertTrue(contactId1 != contactId2);
    895 
    896         assertSuggestions(contactId1, contactId2);
    897     }
    898 
    899     public void testAggregationSuggestionsBasedOnEmailAddress() {
    900 
    901         // Create two contacts that would not be aggregated because of name mismatch
    902         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
    903         DataUtil.insertStructuredName(mResolver, rawContactId1, "Carl", "Fredricksen");
    904         insertEmail(rawContactId1, "up (at) android.com");
    905 
    906         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
    907         DataUtil.insertStructuredName(mResolver, rawContactId2, "Charles", "Muntz");
    908         insertEmail(rawContactId2, "up (at) android.com");
    909 
    910         long contactId1 = queryContactId(rawContactId1);
    911         long contactId2 = queryContactId(rawContactId2);
    912         assertTrue(contactId1 != contactId2);
    913 
    914         assertSuggestions(contactId1, contactId2);
    915     }
    916 
    917     public void testAggregationSuggestionsBasedOnEmailAddressApproximateMatch() {
    918 
    919         // Create two contacts that would not be aggregated because of name mismatch
    920         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
    921         DataUtil.insertStructuredName(mResolver, rawContactId1, "Bob", null);
    922         insertEmail(rawContactId1, "incredible (at) android.com");
    923 
    924         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
    925         DataUtil.insertStructuredName(mResolver, rawContactId2, "Lucius", "Best");
    926         insertEmail(rawContactId2, "incrediball (at) android.com");
    927 
    928         long contactId1 = queryContactId(rawContactId1);
    929         long contactId2 = queryContactId(rawContactId2);
    930         assertTrue(contactId1 != contactId2);
    931 
    932         assertSuggestions(contactId1, contactId2);
    933     }
    934 
    935     public void testAggregationSuggestionsBasedOnNickname() {
    936         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
    937         DataUtil.insertStructuredName(mResolver, rawContactId1, "Peter", "Parker");
    938         insertNickname(rawContactId1, "Spider-Man");
    939 
    940         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
    941         DataUtil.insertStructuredName(mResolver, rawContactId2, "Manny", "Spider");
    942 
    943         long contactId1 = queryContactId(rawContactId1);
    944         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    945                 rawContactId1, rawContactId2);
    946 
    947         long contactId2 = queryContactId(rawContactId2);
    948         assertSuggestions(contactId1, contactId2);
    949     }
    950 
    951     public void testAggregationSuggestionsBasedOnNicknameMatchingName() {
    952         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
    953         DataUtil.insertStructuredName(mResolver, rawContactId1, "Clark", "Kent");
    954         insertNickname(rawContactId1, "Superman");
    955 
    956         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
    957         DataUtil.insertStructuredName(mResolver, rawContactId2, "Roy", "Williams");
    958         insertNickname(rawContactId2, "superman");
    959 
    960         long contactId1 = queryContactId(rawContactId1);
    961         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    962                 rawContactId1, rawContactId2);
    963 
    964         long contactId2 = queryContactId(rawContactId2);
    965         assertSuggestions(contactId1, contactId2);
    966     }
    967 
    968     public void testAggregationSuggestionsBasedOnCommonNickname() {
    969         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
    970         DataUtil.insertStructuredName(mResolver, rawContactId1, "Dick", "Cherry");
    971 
    972         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
    973         DataUtil.insertStructuredName(mResolver, rawContactId2, "Richard", "Cherry");
    974 
    975         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
    976                 rawContactId1, rawContactId2);
    977 
    978         long contactId1 = queryContactId(rawContactId1);
    979         long contactId2 = queryContactId(rawContactId2);
    980         assertSuggestions(contactId1, contactId2);
    981     }
    982 
    983     public void testAggregationSuggestionsBasedOnPhoneNumberWithFilter() {
    984 
    985         // Create two contacts that would not be aggregated because of name mismatch
    986         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
    987         DataUtil.insertStructuredName(mResolver, rawContactId1, "Lord", "Farquaad");
    988         insertPhoneNumber(rawContactId1, "(888)555-1236");
    989 
    990         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
    991         DataUtil.insertStructuredName(mResolver, rawContactId2, "Talking", "Donkey");
    992         insertPhoneNumber(rawContactId2, "1(888)555-1236");
    993 
    994         long contactId1 = queryContactId(rawContactId1);
    995         long contactId2 = queryContactId(rawContactId2);
    996         assertTrue(contactId1 != contactId2);
    997 
    998         assertSuggestions(contactId1, "talk", contactId2);
    999         assertSuggestions(contactId1, "don", contactId2);
   1000         assertSuggestions(contactId1, "", contactId2);
   1001         assertSuggestions(contactId1, "eddie");
   1002     }
   1003 
   1004     public void testAggregationSuggestionsDontSuggestInvisible() {
   1005         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "first", "last",
   1006                 ACCOUNT_1);
   1007         insertPhoneNumber(rawContactId1, "111-222-3333");
   1008         insertNickname(rawContactId1, "Superman");
   1009         insertEmail(rawContactId1, "incredible (at) android.com");
   1010 
   1011         // Create another with the exact same name, phone number, nickname and email.
   1012         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "first", "last",
   1013                 ACCOUNT_2);
   1014         insertPhoneNumber(rawContactId2, "111-222-3333");
   1015         insertNickname(rawContactId2, "Superman");
   1016         insertEmail(rawContactId2, "incredible (at) android.com");
   1017 
   1018         // The aggregator should have joined them.  Split them up.
   1019         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
   1020                 rawContactId1, rawContactId2);
   1021 
   1022         long contactId1 = queryContactId(rawContactId1);
   1023         long contactId2 = queryContactId(rawContactId2);
   1024 
   1025         // Make sure they're different contacts.
   1026         MoreAsserts.assertNotEqual(contactId1, contactId2);
   1027 
   1028         // Contact 2 should be suggested.
   1029         assertSuggestions(contactId1, contactId2);
   1030 
   1031         // Make contact 2 invisible.
   1032         markInvisible(contactId2);
   1033 
   1034         // Now contact 2 shuldn't be suggested.
   1035         assertSuggestions(contactId1, new long[0]);
   1036     }
   1037 
   1038     public void testChoosePhotoSetBeforeAggregation() {
   1039         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
   1040         setContactAccount(rawContactId1, "donut", "donut_act");
   1041         insertPhoto(rawContactId1);
   1042 
   1043         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
   1044         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
   1045         long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2));
   1046 
   1047         long rawContactId3 = RawContactUtil.createRawContact(mResolver);
   1048         setContactAccount(rawContactId3, "froyo", "froyo_act");
   1049         insertPhoto(rawContactId3);
   1050 
   1051         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1052                 rawContactId1, rawContactId2);
   1053         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1054                 rawContactId1, rawContactId3);
   1055         assertEquals(cupcakeId, queryPhotoId(queryContactId(rawContactId2)));
   1056     }
   1057 
   1058     public void testChoosePhotoSetAfterAggregation() {
   1059         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
   1060         setContactAccount(rawContactId1, "donut", "donut_act");
   1061         insertPhoto(rawContactId1);
   1062 
   1063         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
   1064         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1065                 rawContactId1, rawContactId2);
   1066         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
   1067         long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2));
   1068 
   1069         long rawContactId3 = RawContactUtil.createRawContact(mResolver);
   1070         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1071                 rawContactId1, rawContactId3);
   1072         setContactAccount(rawContactId3, "froyo", "froyo_act");
   1073         insertPhoto(rawContactId3);
   1074 
   1075         assertEquals(cupcakeId, queryPhotoId(queryContactId(rawContactId2)));
   1076     }
   1077 
   1078     // Note that for the following tests of photo aggregation, the accounts are being used to
   1079     // set the typical photo priority that each raw contact would have, based on
   1080     // SynchronousContactsProvider2.createPhotoPriorityResolver.  The relative priorities
   1081     // specified there are:
   1082     // cupcake: 3
   1083     // donut: 2
   1084     // froyo: 1
   1085     // <other>: 0
   1086 
   1087     public void testChooseLargerPhotoByDimensions() {
   1088         // Donut photo is 256x256.
   1089         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
   1090         setContactAccount(rawContactId1, "donut", "donut_act");
   1091         long normalEarthDataId = ContentUris.parseId(
   1092                 insertPhoto(rawContactId1, R.drawable.earth_normal));
   1093         long normalEarthPhotoFileId = getStoredLongValue(
   1094                 ContentUris.withAppendedId(Data.CONTENT_URI, normalEarthDataId),
   1095                 Photo.PHOTO_FILE_ID);
   1096 
   1097         // Cupcake would normally have priority, but its photo is 200x200.
   1098         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
   1099         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
   1100         insertPhoto(rawContactId2, R.drawable.earth_200);
   1101 
   1102         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1103                 rawContactId1, rawContactId2);
   1104 
   1105         // Larger photo (by dimensions) wins.
   1106         assertEquals(normalEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1)));
   1107     }
   1108 
   1109     public void testChooseLargerPhotoByFileSize() {
   1110         // Donut photo is a 256x256 photo of a nebula.
   1111         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
   1112         setContactAccount(rawContactId1, "donut", "donut_act");
   1113         long nebulaDataId = ContentUris.parseId(
   1114                 insertPhoto(rawContactId1, R.drawable.nebula));
   1115         long nebulaPhotoFileId = getStoredLongValue(
   1116                 ContentUris.withAppendedId(Data.CONTENT_URI, nebulaDataId),
   1117                 Photo.PHOTO_FILE_ID);
   1118 
   1119         // Cupcake would normally have priority, but its photo (of a galaxy) has the same dimensions
   1120         // as Donut's, but a smaller filesize.
   1121         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
   1122         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
   1123         insertPhoto(rawContactId2, R.drawable.galaxy);
   1124 
   1125         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1126                 rawContactId1, rawContactId2);
   1127 
   1128         // Larger photo (by filesize) wins.
   1129         assertEquals(nebulaPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1)));
   1130     }
   1131 
   1132     public void testChooseFilePhotoOverThumbnail() {
   1133         // Donut photo is a 256x256 photo of Earth.
   1134         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
   1135         setContactAccount(rawContactId1, "donut", "donut_act");
   1136         long normalEarthDataId = ContentUris.parseId(
   1137                 insertPhoto(rawContactId1, R.drawable.earth_normal));
   1138         long normalEarthPhotoFileId = getStoredLongValue(
   1139                 ContentUris.withAppendedId(Data.CONTENT_URI, normalEarthDataId),
   1140                 Photo.PHOTO_FILE_ID);
   1141 
   1142         // Cupcake would normally have priority, but its photo of Earth is thumbnail-sized.
   1143         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
   1144         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
   1145         insertPhoto(rawContactId2, R.drawable.earth_small);
   1146 
   1147         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1148                 rawContactId1, rawContactId2);
   1149 
   1150         // Larger photo (by filesize) wins.
   1151         assertEquals(normalEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1)));
   1152     }
   1153 
   1154     public void testFallbackToAccountPriorityForSamePhoto() {
   1155         // Donut photo is a 256x256 photo of Earth.
   1156         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
   1157         setContactAccount(rawContactId1, "donut", "donut_act");
   1158         insertPhoto(rawContactId1, R.drawable.earth_normal);
   1159 
   1160         // Cupcake has the same 256x256 photo of Earth.
   1161         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
   1162         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
   1163         long cupcakeEarthDataId = ContentUris.parseId(
   1164                 insertPhoto(rawContactId2, R.drawable.earth_normal));
   1165         long cupcakeEarthPhotoFileId = getStoredLongValue(
   1166                 ContentUris.withAppendedId(Data.CONTENT_URI, cupcakeEarthDataId),
   1167                 Photo.PHOTO_FILE_ID);
   1168 
   1169         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1170                 rawContactId1, rawContactId2);
   1171 
   1172         // Cupcake's version of the photo wins, falling back to account priority.
   1173         assertEquals(cupcakeEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1)));
   1174     }
   1175 
   1176     public void testFallbackToAccountPriorityForDifferingThumbnails() {
   1177         // Donut photo is a 96x96 thumbnail of Earth.
   1178         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
   1179         setContactAccount(rawContactId1, "donut", "donut_act");
   1180         insertPhoto(rawContactId1, R.drawable.earth_small);
   1181 
   1182         // Cupcake photo is the 96x96 "no contact" placeholder (smaller filesize than the Earth
   1183         // picture, but thumbnail filesizes are ignored in the aggregator).
   1184         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
   1185         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
   1186         long cupcakeDataId = ContentUris.parseId(
   1187                 insertPhoto(rawContactId2, R.drawable.ic_contact_picture));
   1188 
   1189         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
   1190                 rawContactId1, rawContactId2);
   1191 
   1192         // The Cupcake thumbnail wins, by account priority..
   1193         assertEquals(cupcakeDataId, queryPhotoId(queryContactId(rawContactId1)));
   1194     }
   1195 
   1196     public void testDisplayNameSources() {
   1197         long rawContactId = RawContactUtil.createRawContact(mResolver);
   1198         long contactId = queryContactId(rawContactId);
   1199 
   1200         assertNull(queryDisplayName(contactId));
   1201 
   1202         insertEmail(rawContactId, "eclair (at) android.com");
   1203         assertEquals("eclair (at) android.com", queryDisplayName(contactId));
   1204 
   1205         insertPhoneNumber(rawContactId, "800-555-5555");
   1206         assertEquals("800-555-5555", queryDisplayName(contactId));
   1207 
   1208         ContentValues values = new ContentValues();
   1209         values.put(Organization.COMPANY, "Android");
   1210         insertOrganization(rawContactId, values);
   1211         assertEquals("Android", queryDisplayName(contactId));
   1212 
   1213         insertNickname(rawContactId, "Dro");
   1214         assertEquals("Dro", queryDisplayName(contactId));
   1215 
   1216         values.clear();
   1217         values.put(StructuredName.GIVEN_NAME, "Eclair");
   1218         values.put(StructuredName.FAMILY_NAME, "Android");
   1219         DataUtil.insertStructuredName(mResolver, rawContactId, values);
   1220         assertEquals("Eclair Android", queryDisplayName(contactId));
   1221     }
   1222 
   1223     public void testVerifiedName() {
   1224         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "test1", "TEST1",
   1225                 ACCOUNT_1);
   1226         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.NAME_VERIFIED, "1");
   1227         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "test2", "TEST2",
   1228                 ACCOUNT_2);
   1229         long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "test3",
   1230                 "TEST3 LONG", ACCOUNT_3);
   1231 
   1232         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1,
   1233                 rawContactId2);
   1234         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1,
   1235                 rawContactId3);
   1236 
   1237         long contactId = queryContactId(rawContactId1);
   1238 
   1239         // Should be the verified name
   1240         assertEquals("test1 TEST1", queryDisplayName(contactId));
   1241 
   1242         // Mark a different name as verified - this should reset the NAME_VERIFIED field
   1243         // for the other rawContacts
   1244         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.NAME_VERIFIED, "1");
   1245         assertStoredValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.NAME_VERIFIED, 0);
   1246         assertEquals("test2 TEST2", queryDisplayName(contactId));
   1247 
   1248         // Reset the NAME_VERIFIED flag - now the most complex of the three names should win
   1249         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.NAME_VERIFIED, "0");
   1250         assertEquals("test3 TEST3 LONG", queryDisplayName(contactId));
   1251     }
   1252 
   1253     public void testAggregationModeSuspendedSeparateTransactions() {
   1254 
   1255         // Setting aggregation mode to SUSPENDED should prevent aggregation from happening
   1256         long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
   1257         storeValue(RawContacts.CONTENT_URI, rawContactId1,
   1258                 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
   1259         Uri name1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "THE", "SAME");
   1260 
   1261         long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
   1262         storeValue(RawContacts.CONTENT_URI, rawContactId2,
   1263                 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
   1264         DataUtil.insertStructuredName(mResolver, rawContactId2, "THE", "SAME");
   1265 
   1266         assertNotAggregated(rawContactId1, rawContactId2);
   1267 
   1268         // Changing aggregation mode to DEFAULT should change nothing
   1269         storeValue(RawContacts.CONTENT_URI, rawContactId1,
   1270                 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT);
   1271         storeValue(RawContacts.CONTENT_URI, rawContactId2,
   1272                 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT);
   1273         assertNotAggregated(rawContactId1, rawContactId2);
   1274 
   1275         // Changing the name should trigger aggregation
   1276         storeValue(name1, StructuredName.GIVEN_NAME, "the");
   1277         assertAggregated(rawContactId1, rawContactId2);
   1278     }
   1279 
   1280     public void testAggregationModeInitializedAsSuspended() throws Exception {
   1281 
   1282         // Setting aggregation mode to SUSPENDED should prevent aggregation from happening
   1283         ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
   1284                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
   1285                 .build();
   1286         ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
   1287                 .withValueBackReference(Data.RAW_CONTACT_ID, 0)
   1288                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
   1289                 .withValue(StructuredName.GIVEN_NAME, "John")
   1290                 .withValue(StructuredName.FAMILY_NAME, "Doe")
   1291                 .build();
   1292         ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
   1293                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
   1294                 .build();
   1295         ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
   1296                 .withValueBackReference(Data.RAW_CONTACT_ID, 2)
   1297                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
   1298                 .withValue(StructuredName.GIVEN_NAME, "John")
   1299                 .withValue(StructuredName.FAMILY_NAME, "Doe")
   1300                 .build();
   1301         ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
   1302                 .withSelection(RawContacts._ID + "=?", new String[1])
   1303                 .withSelectionBackReference(0, 0)
   1304                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT)
   1305                 .build();
   1306         ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
   1307                 .withSelection(RawContacts._ID + "=?", new String[1])
   1308                 .withSelectionBackReference(0, 2)
   1309                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT)
   1310                 .build();
   1311 
   1312         ContentProviderResult[] results =
   1313                 mResolver.applyBatch(ContactsContract.AUTHORITY,
   1314                         Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6));
   1315 
   1316         long rawContactId1 = ContentUris.parseId(results[0].uri);
   1317         long rawContactId2 = ContentUris.parseId(results[2].uri);
   1318 
   1319         assertNotAggregated(rawContactId1, rawContactId2);
   1320     }
   1321 
   1322     public void testAggregationModeUpdatedToSuspended() throws Exception {
   1323 
   1324         // Setting aggregation mode to SUSPENDED should prevent aggregation from happening
   1325         ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
   1326                 .withValues(new ContentValues())
   1327                 .build();
   1328         ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
   1329                 .withValueBackReference(Data.RAW_CONTACT_ID, 0)
   1330                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
   1331                 .withValue(StructuredName.GIVEN_NAME, "John")
   1332                 .withValue(StructuredName.FAMILY_NAME, "Doe")
   1333                 .build();
   1334         ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
   1335                 .withValues(new ContentValues())
   1336                 .build();
   1337         ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
   1338                 .withValueBackReference(Data.RAW_CONTACT_ID, 2)
   1339                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
   1340                 .withValue(StructuredName.GIVEN_NAME, "John")
   1341                 .withValue(StructuredName.FAMILY_NAME, "Doe")
   1342                 .build();
   1343         ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
   1344                 .withSelection(RawContacts._ID + "=?", new String[1])
   1345                 .withSelectionBackReference(0, 0)
   1346                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
   1347                 .build();
   1348         ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
   1349                 .withSelection(RawContacts._ID + "=?", new String[1])
   1350                 .withSelectionBackReference(0, 2)
   1351                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
   1352                 .build();
   1353 
   1354         ContentProviderResult[] results =
   1355                 mResolver.applyBatch(ContactsContract.AUTHORITY,
   1356                         Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6));
   1357 
   1358         long rawContactId1 = ContentUris.parseId(results[0].uri);
   1359         long rawContactId2 = ContentUris.parseId(results[2].uri);
   1360 
   1361         assertNotAggregated(rawContactId1, rawContactId2);
   1362     }
   1363 
   1364     public void testAggregationModeSuspendedOverriddenByAggException() throws Exception {
   1365         ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
   1366                 .withValue(RawContacts.ACCOUNT_NAME, "a")
   1367                 .withValue(RawContacts.ACCOUNT_TYPE, "b")
   1368                 .build();
   1369         ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
   1370                 .withValueBackReference(Data.RAW_CONTACT_ID, 0)
   1371                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
   1372                 .withValue(StructuredName.GIVEN_NAME, "John")
   1373                 .withValue(StructuredName.FAMILY_NAME, "Doe")
   1374                 .build();
   1375         ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
   1376                 .withValue(RawContacts.ACCOUNT_NAME, "c")
   1377                 .withValue(RawContacts.ACCOUNT_TYPE, "d")
   1378                 .build();
   1379         ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI)
   1380                 .withValueBackReference(Data.RAW_CONTACT_ID, 2)
   1381                 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
   1382                 .withValue(StructuredName.GIVEN_NAME, "John")
   1383                 .withValue(StructuredName.FAMILY_NAME, "Doe")
   1384                 .build();
   1385         ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
   1386                 .withSelection(RawContacts._ID + "=?", new String[1])
   1387                 .withSelectionBackReference(0, 0)
   1388                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
   1389                 .build();
   1390         ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
   1391                 .withSelection(RawContacts._ID + "=?", new String[1])
   1392                 .withSelectionBackReference(0, 2)
   1393                 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)
   1394                 .build();
   1395 
   1396         // Checking that aggregation mode SUSPENDED should be overridden by inserting
   1397         // an explicit aggregation exception
   1398         ContentProviderOperation cpo7 =
   1399                 ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI)
   1400                 .withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, 0)
   1401                 .withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, 2)
   1402                 .withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER)
   1403                 .build();
   1404 
   1405         ContentProviderResult[] results =
   1406                 mResolver.applyBatch(ContactsContract.AUTHORITY,
   1407                         Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6, cpo7));
   1408 
   1409         long rawContactId1 = ContentUris.parseId(results[0].uri);
   1410         long rawContactId2 = ContentUris.parseId(results[2].uri);
   1411 
   1412         assertAggregated(rawContactId1, rawContactId2);
   1413     }
   1414 
   1415     public void testAggregationSuggestionsQueryBuilderWithContactId() throws Exception {
   1416         Uri uri = AggregationSuggestions.builder().setContactId(12).setLimit(7).build();
   1417         assertEquals("content://com.android.contacts/contacts/12/suggestions?limit=7",
   1418                 uri.toString());
   1419     }
   1420 
   1421     public void testAggregationSuggestionsQueryBuilderWithValues() throws Exception {
   1422         Uri uri = AggregationSuggestions.builder()
   1423                 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "name1")
   1424                 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "name2")
   1425                 .addParameter(AggregationSuggestions.PARAMETER_MATCH_EMAIL, "email1")
   1426                 .addParameter(AggregationSuggestions.PARAMETER_MATCH_EMAIL, "email2")
   1427                 .addParameter(AggregationSuggestions.PARAMETER_MATCH_PHONE, "phone1")
   1428                 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NICKNAME, "nickname1")
   1429                 .setLimit(7)
   1430                 .build();
   1431         assertEquals("content://com.android.contacts/contacts/0/suggestions?"
   1432                 + "limit=7"
   1433                 + "&query=name%3Aname1"
   1434                 + "&query=name%3Aname2"
   1435                 + "&query=email%3Aemail1"
   1436                 + "&query=email%3Aemail2"
   1437                 + "&query=phone%3Aphone1"
   1438                 + "&query=nickname%3Anickname1", uri.toString());
   1439     }
   1440 
   1441     public void testAggregatedStatusUpdate() {
   1442         long rawContactId1 = RawContactUtil.createRawContact(mResolver);
   1443         Uri dataUri1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "john", "doe");
   1444         insertStatusUpdate(ContentUris.parseId(dataUri1), StatusUpdates.AWAY, "Green", 100,
   1445                 StatusUpdates.CAPABILITY_HAS_CAMERA);
   1446         long rawContactId2 = RawContactUtil.createRawContact(mResolver);
   1447         Uri dataUri2 = DataUtil.insertStructuredName(mResolver, rawContactId2, "john", "doe");
   1448         insertStatusUpdate(ContentUris.parseId(dataUri2), StatusUpdates.AVAILABLE, "Red", 50,
   1449                 StatusUpdates.CAPABILITY_HAS_CAMERA);
   1450         setAggregationException(
   1451                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
   1452 
   1453         assertStoredValue(getContactUriForRawContact(rawContactId1),
   1454                 Contacts.CONTACT_STATUS, "Green");
   1455 
   1456         // When we split these two raw contacts, their respective statuses should be restored
   1457         setAggregationException(
   1458                 AggregationExceptions.TYPE_KEEP_SEPARATE, rawContactId1, rawContactId2);
   1459 
   1460         assertStoredValue(getContactUriForRawContact(rawContactId1),
   1461                 Contacts.CONTACT_STATUS, "Green");
   1462 
   1463         assertStoredValue(getContactUriForRawContact(rawContactId2),
   1464                 Contacts.CONTACT_STATUS, "Red");
   1465     }
   1466 
   1467     public void testAggregationSuggestionsByName() throws Exception {
   1468         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "first1", "last1");
   1469         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "first2", "last2");
   1470 
   1471         Uri uri = AggregationSuggestions.builder()
   1472                 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "last1 first1")
   1473                 .build();
   1474 
   1475         Cursor cursor = mResolver.query(
   1476                 uri, new String[] { Contacts._ID, Contacts.DISPLAY_NAME }, null, null, null);
   1477 
   1478         assertEquals(1, cursor.getCount());
   1479 
   1480         cursor.moveToFirst();
   1481 
   1482         ContentValues values = new ContentValues();
   1483         values.put(Contacts._ID, queryContactId(rawContactId1));
   1484         values.put(Contacts.DISPLAY_NAME, "first1 last1");
   1485         assertCursorValues(cursor, values);
   1486         cursor.close();
   1487     }
   1488 
   1489     private void assertSuggestions(long contactId, long... suggestions) {
   1490         final Uri aggregateUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1491         Uri uri = Uri.withAppendedPath(aggregateUri,
   1492                 Contacts.AggregationSuggestions.CONTENT_DIRECTORY);
   1493         assertSuggestions(uri, suggestions);
   1494     }
   1495 
   1496     private void assertSuggestions(long contactId, String filter, long... suggestions) {
   1497         final Uri aggregateUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
   1498         Uri uri = Uri.withAppendedPath(Uri.withAppendedPath(aggregateUri,
   1499                 Contacts.AggregationSuggestions.CONTENT_DIRECTORY), Uri.encode(filter));
   1500         assertSuggestions(uri, suggestions);
   1501     }
   1502 
   1503     private void assertSuggestions(Uri uri, long... suggestions) {
   1504         final Cursor cursor = mResolver.query(uri,
   1505                 new String[] { Contacts._ID, Contacts.CONTACT_PRESENCE },
   1506                 null, null, null);
   1507 
   1508         try {
   1509             assertEquals(suggestions.length, cursor.getCount());
   1510 
   1511             for (int i = 0; i < suggestions.length; i++) {
   1512                 cursor.moveToNext();
   1513                 assertEquals(suggestions[i], cursor.getLong(0));
   1514             }
   1515         } finally {
   1516             TestUtils.dumpCursor(cursor);
   1517         }
   1518 
   1519         cursor.close();
   1520     }
   1521 
   1522     private void assertDisplayNameEquals(long contactId, long rawContactId) {
   1523 
   1524         String contactDisplayName = queryDisplayName(contactId);
   1525 
   1526         Cursor c = queryRawContact(rawContactId);
   1527         assertTrue(c.moveToFirst());
   1528         String rawDisplayName = c.getString(c.getColumnIndex(RawContacts.DISPLAY_NAME_PRIMARY));
   1529         c.close();
   1530 
   1531         assertTrue(contactDisplayName != null);
   1532         assertTrue(rawDisplayName != null);
   1533         assertEquals(rawDisplayName, contactDisplayName);
   1534     }
   1535 }
   1536