| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.providers.contacts.aggregation; |
| |
| import android.accounts.Account; |
| import android.content.ContentProviderOperation; |
| import android.content.ContentProviderResult; |
| import android.content.ContentUris; |
| import android.content.ContentValues; |
| import android.database.Cursor; |
| import android.net.Uri; |
| import android.provider.ContactsContract; |
| import android.provider.ContactsContract.AggregationExceptions; |
| import android.provider.ContactsContract.CommonDataKinds.Organization; |
| import android.provider.ContactsContract.CommonDataKinds.StructuredName; |
| import android.provider.ContactsContract.Contacts; |
| import android.provider.ContactsContract.Contacts.AggregationSuggestions; |
| import android.provider.ContactsContract.Contacts.Photo; |
| import android.provider.ContactsContract.Data; |
| import android.provider.ContactsContract.RawContacts; |
| import android.provider.ContactsContract.StatusUpdates; |
| import android.test.MoreAsserts; |
| import android.test.suitebuilder.annotation.MediumTest; |
| |
| import com.android.providers.contacts.BaseContactsProvider2Test; |
| import com.android.providers.contacts.TestUtils; |
| import com.android.providers.contacts.tests.R; |
| import com.android.providers.contacts.testutil.DataUtil; |
| import com.android.providers.contacts.testutil.RawContactUtil; |
| |
| import com.google.android.collect.Lists; |
| import com.google.common.collect.HashMultimap; |
| import com.google.common.collect.Multimap; |
| |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| /** |
| * Unit tests for {@link ContactAggregator}. |
| * |
| * Run the test like this: |
| * <code> |
| * adb shell am instrument -e class com.android.providers.contacts.ContactAggregatorTest -w \ |
| * com.android.providers.contacts.tests/android.test.InstrumentationTestRunner |
| * </code> |
| */ |
| @MediumTest |
| public class ContactAggregatorTest extends BaseContactsProvider2Test { |
| |
| private static final Account ACCOUNT_1 = new Account("account_name_1", "account_type_1"); |
| private static final Account ACCOUNT_2 = new Account("account_name_2", "account_type_2"); |
| private static final Account ACCOUNT_3 = new Account("account_name_3", "account_type_3"); |
| |
| private static final String[] AGGREGATION_EXCEPTION_PROJECTION = new String[] { |
| AggregationExceptions.TYPE, |
| AggregationExceptions.RAW_CONTACT_ID1, |
| AggregationExceptions.RAW_CONTACT_ID2 |
| }; |
| |
| public void testCrudAggregationExceptions() throws Exception { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "zz", "top"); |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "aa", "bottom"); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId2); |
| |
| String selection = "(" + AggregationExceptions.RAW_CONTACT_ID1 + "=" + rawContactId1 |
| + " AND " + AggregationExceptions.RAW_CONTACT_ID2 + "=" + rawContactId2 |
| + ") OR (" + AggregationExceptions.RAW_CONTACT_ID1 + "=" + rawContactId2 |
| + " AND " + AggregationExceptions.RAW_CONTACT_ID2 + "=" + rawContactId1 + ")"; |
| |
| // Refetch the row we have just inserted |
| Cursor c = mResolver.query(AggregationExceptions.CONTENT_URI, |
| AGGREGATION_EXCEPTION_PROJECTION, selection, null, null); |
| |
| assertTrue(c.moveToFirst()); |
| assertEquals(AggregationExceptions.TYPE_KEEP_TOGETHER, c.getInt(0)); |
| assertTrue((rawContactId1 == c.getLong(1) && rawContactId2 == c.getLong(2)) |
| || (rawContactId2 == c.getLong(1) && rawContactId1 == c.getLong(2))); |
| assertFalse(c.moveToNext()); |
| c.close(); |
| |
| // Change from TYPE_KEEP_IN to TYPE_KEEP_OUT |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId1, rawContactId2); |
| |
| c = mResolver.query(AggregationExceptions.CONTENT_URI, AGGREGATION_EXCEPTION_PROJECTION, |
| selection, null, null); |
| |
| assertTrue(c.moveToFirst()); |
| assertEquals(AggregationExceptions.TYPE_KEEP_SEPARATE, c.getInt(0)); |
| assertTrue((rawContactId1 == c.getLong(1) && rawContactId2 == c.getLong(2)) |
| || (rawContactId2 == c.getLong(1) && rawContactId1 == c.getLong(2))); |
| assertFalse(c.moveToNext()); |
| c.close(); |
| |
| // Delete the rule |
| setAggregationException(AggregationExceptions.TYPE_AUTOMATIC, |
| rawContactId1, rawContactId2); |
| |
| // Verify that the row is gone |
| c = mResolver.query(AggregationExceptions.CONTENT_URI, AGGREGATION_EXCEPTION_PROJECTION, |
| selection, null, null); |
| assertFalse(c.moveToFirst()); |
| c.close(); |
| } |
| |
| public void testAggregationCreatesNewAggregate() { |
| long rawContactId = RawContactUtil.createRawContact(mResolver); |
| |
| Uri resultUri = DataUtil.insertStructuredName(mResolver, rawContactId, "Johna", "Smitha"); |
| |
| // Parse the URI and confirm that it contains an ID |
| assertTrue(ContentUris.parseId(resultUri) != 0); |
| |
| long contactId = queryContactId(rawContactId); |
| assertTrue(contactId != 0); |
| |
| String displayName = queryDisplayName(contactId); |
| assertEquals("Johna Smitha", displayName); |
| } |
| |
| public void testAggregationOfExactFullNameMatch() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnb", "Smithb"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnb", "Smithb"); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Johnb Smithb"); |
| } |
| |
| public void testAggregationIgnoresInvisibleContact() { |
| Account account = new Account("accountName", "accountType"); |
| createAutoAddGroup(account); |
| |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, account); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder"); |
| |
| // Hide by removing from all groups |
| removeGroupMemberships(rawContactId1); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, account); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder"); |
| |
| long rawContactId3 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertAggregated(rawContactId2, rawContactId3, "Flynn Ryder"); |
| } |
| |
| public void testAggregationOfCaseInsensitiveFullNameMatch() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnc", "Smithc"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnc", "smithc"); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Johnc Smithc"); |
| } |
| |
| public void testAggregationOfLastNameMatch() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, null, "Johnd"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, null, "johnd"); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Johnd"); |
| } |
| |
| public void testNonAggregationOfFirstNameMatch() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Johne", "Smithe"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Johne", null); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testNonAggregationOfLastNameMatch() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnf", "Smithf"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, null, "Smithf"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationOfConcatenatedFullNameMatch() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Johng", "Smithg"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "johngsmithg", null); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Johng Smithg"); |
| } |
| |
| public void testAggregationOfNormalizedFullNameMatch() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "H\u00e9l\u00e8ne", "Bj\u00f8rn"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "helene bjorn", null); |
| |
| assertAggregated(rawContactId1, rawContactId2, "H\u00e9l\u00e8ne Bj\u00f8rn"); |
| } |
| |
| public void testAggregationOfNormalizedFullNameMatchWithReadOnlyAccount() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, new Account("acct", |
| READ_ONLY_ACCOUNT_TYPE)); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "H\u00e9l\u00e8ne", "Bj\u00f8rn"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "helene bjorn", null); |
| |
| assertAggregated(rawContactId1, rawContactId2, "helene bjorn"); |
| } |
| |
| public void testAggregationOfNumericNames() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "123", null); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "1-2-3", null); |
| |
| assertAggregated(rawContactId1, rawContactId2, "1-2-3"); |
| } |
| |
| public void testAggregationOfInconsistentlyParsedNames() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| |
| ContentValues values = new ContentValues(); |
| values.put(StructuredName.DISPLAY_NAME, "604 Arizona Ave"); |
| values.put(StructuredName.GIVEN_NAME, "604"); |
| values.put(StructuredName.MIDDLE_NAME, "Arizona"); |
| values.put(StructuredName.FAMILY_NAME, "Ave"); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, values); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| values.clear(); |
| values.put(StructuredName.DISPLAY_NAME, "604 Arizona Ave"); |
| values.put(StructuredName.GIVEN_NAME, "604"); |
| values.put(StructuredName.FAMILY_NAME, "Arizona Ave"); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, values); |
| |
| assertAggregated(rawContactId1, rawContactId2, "604 Arizona Ave"); |
| } |
| |
| public void testAggregationBasedOnMiddleName() { |
| ContentValues values = new ContentValues(); |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| values.put(StructuredName.GIVEN_NAME, "John"); |
| values.put(StructuredName.GIVEN_NAME, "Abigale"); |
| values.put(StructuredName.FAMILY_NAME, "James"); |
| |
| DataUtil.insertStructuredName(mResolver, rawContactId1, values); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| values.clear(); |
| values.put(StructuredName.GIVEN_NAME, "John"); |
| values.put(StructuredName.GIVEN_NAME, "Marie"); |
| values.put(StructuredName.FAMILY_NAME, "James"); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, values); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationBasedOnPhoneNumberNoNameData() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| insertPhoneNumber(rawContactId1, "(888)555-1231"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| insertPhoneNumber(rawContactId2, "1(888)555-1231"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationBasedOnPhoneNumberWhenTargetAggregateHasNoName() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| insertPhoneNumber(rawContactId1, "(888)555-1232"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnl", "Smithl"); |
| insertPhoneNumber(rawContactId2, "1(888)555-1232"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationBasedOnPhoneNumberWhenNewContactHasNoName() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnm", "Smithm"); |
| insertPhoneNumber(rawContactId1, "(888)555-1233"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| insertPhoneNumber(rawContactId2, "1(888)555-1233"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationBasedOnPhoneNumberWithDifferentNames() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Baby", "Bear"); |
| insertPhoneNumber(rawContactId1, "(888)555-1235"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Blind", "Mouse"); |
| insertPhoneNumber(rawContactId2, "1(888)555-1235"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationBasedOnPhoneNumberWithJustFirstName() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Chick", "Notnull"); |
| insertPhoneNumber(rawContactId1, "(888)555-1236"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Chick", null); |
| insertPhoneNumber(rawContactId2, "1(888)555-1236"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationBasedOnEmailNoNameData() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| insertEmail(rawContactId1, "lightning@android.com"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| insertEmail(rawContactId2, "lightning@android.com"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationBasedOnEmailWhenTargetAggregateHasNoName() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| insertEmail(rawContactId1, "mcqueen@android.com"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Lightning", "McQueen"); |
| insertEmail(rawContactId2, "mcqueen@android.com"); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Lightning McQueen"); |
| } |
| |
| public void testAggregationBasedOnEmailWhenNewContactHasNoName() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Doc", "Hudson"); |
| insertEmail(rawContactId1, "doc@android.com"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| insertEmail(rawContactId2, "doc@android.com"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationBasedOnEmailWithDifferentNames() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Chick", "Hicks"); |
| insertEmail(rawContactId1, "hicky@android.com"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Luigi", "Guido"); |
| insertEmail(rawContactId2, "hicky@android.com"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationByCommonNicknameWithLastName() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Bill", "Gore"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "William", "Gore"); |
| |
| assertAggregated(rawContactId1, rawContactId2, "William Gore"); |
| } |
| |
| public void testAggregationByCommonNicknameOnly() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Lawrence", null); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Larry", null); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Lawrence"); |
| } |
| |
| public void testAggregationByNicknameNoStructuredName() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| insertNickname(rawContactId1, "Frozone"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| insertNickname(rawContactId2, "Frozone"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationByNicknameWithDifferentNames() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Helen", "Parr"); |
| insertNickname(rawContactId1, "Elastigirl"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Shawn", "Johnson"); |
| insertNickname(rawContactId2, "Elastigirl"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testNonAggregationOnOrganization() { |
| ContentValues values = new ContentValues(); |
| values.put(Organization.TITLE, "Monsters, Inc"); |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| insertOrganization(rawContactId1, values); |
| insertNickname(rawContactId1, "Boo"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| insertOrganization(rawContactId2, values); |
| insertNickname(rawContactId2, "Rendall"); // To force reaggregation |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationByIdentity() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| insertIdentity(rawContactId1, "iden1", "namespace1"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| insertIdentity(rawContactId2, "iden1", "namespace1"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationExceptionKeepIn() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnk", "Smithk"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnkx", "Smithkx"); |
| |
| long contactId1 = queryContactId(rawContactId1); |
| long contactId2 = queryContactId(rawContactId2); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId2); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Johnkx Smithkx"); |
| |
| // Assert that the empty aggregate got removed |
| long newContactId1 = queryContactId(rawContactId1); |
| if (contactId1 != newContactId1) { |
| Cursor cursor = queryContact(contactId1); |
| assertFalse(cursor.moveToFirst()); |
| cursor.close(); |
| } else { |
| Cursor cursor = queryContact(contactId2); |
| assertFalse(cursor.moveToFirst()); |
| cursor.close(); |
| } |
| } |
| |
| public void testAggregationExceptionKeepOut() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnh", "Smithh"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnh", "Smithh"); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId1, rawContactId2); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationExceptionKeepOutCheckUpdatesDisplayName() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Johni", "Smithi"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnj", "Smithj"); |
| |
| long rawContactId3 = RawContactUtil.createRawContact(mResolver, ACCOUNT_3); |
| DataUtil.insertStructuredName(mResolver, rawContactId3, "Johnm", "Smithm"); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId2); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId3); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId2, rawContactId3); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Johnm Smithm"); |
| assertAggregated(rawContactId1, rawContactId3); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId1, rawContactId2); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId1, rawContactId3); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| assertNotAggregated(rawContactId1, rawContactId3); |
| |
| String displayName1 = queryDisplayName(queryContactId(rawContactId1)); |
| assertEquals("Johni Smithi", displayName1); |
| |
| assertAggregated(rawContactId2, rawContactId3, "Johnm Smithm"); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId2, rawContactId3); |
| assertNotAggregated(rawContactId1, rawContactId2); |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId2, rawContactId3); |
| |
| String displayName2 = queryDisplayName(queryContactId(rawContactId1)); |
| assertEquals("Johni Smithi", displayName2); |
| |
| String displayName3 = queryDisplayName(queryContactId(rawContactId2)); |
| assertEquals("Johnj Smithj", displayName3); |
| |
| String displayName4 = queryDisplayName(queryContactId(rawContactId3)); |
| assertEquals("Johnm Smithm", displayName4); |
| } |
| |
| public void testAggregationExceptionKeepOutCheckResultDisplayNames() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "c", "c", ACCOUNT_1); |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "b", "b", ACCOUNT_2); |
| long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "a", "a", ACCOUNT_3); |
| |
| // Join all contacts |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId2); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId3); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId2, rawContactId3); |
| |
| // Separate all contacts. The order (2-3 , 1-2, 1-3) is important |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId2, rawContactId3); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId1, rawContactId2); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId1, rawContactId3); |
| |
| // Verify that we have three different contacts |
| long contactId1 = queryContactId(rawContactId1); |
| long contactId2 = queryContactId(rawContactId2); |
| long contactId3 = queryContactId(rawContactId3); |
| |
| assertTrue(contactId1 != contactId2); |
| assertTrue(contactId1 != contactId3); |
| assertTrue(contactId2 != contactId3); |
| |
| // Verify that each raw contact contribute to the contact display name |
| assertDisplayNameEquals(contactId1, rawContactId1); |
| assertDisplayNameEquals(contactId2, rawContactId2); |
| assertDisplayNameEquals(contactId3, rawContactId3); |
| } |
| |
| public void testNonAggregationWithMultipleAffinities() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| assertNotAggregated(rawContactId1, rawContactId2); |
| |
| // There are two aggregates this raw contact could join, so it should join neither |
| long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_2); |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId2, rawContactId3); |
| |
| // Just in case - let's make sure the original two did not get aggregated in the process |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testReaggregateBecauseOfMultipleAffinities() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_2); |
| assertAggregated(rawContactId1, rawContactId2); |
| |
| // The aggregate this raw contact could join has a raw contact from the same account, |
| // The ambiguity will trigger re-aggregation. And since no data matching exists, all |
| // three raw contacts are broken-up. |
| long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId2, rawContactId3); |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregation_notAggregateByPhoneticName() { |
| // Different names, but have the same phonetic name. Shouldn't be aggregated. |
| |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Sergey", null, "Yamada"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Lawrence", null, "Yamada"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregation_notAggregateByPhoneticName_2() { |
| // Have the same phonetic name. One has a regular name too. Shouldn't be aggregated. |
| |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, null, null, "Yamada"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Lawrence", null, "Yamada"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregation_PhoneticNameOnly() { |
| // If a contact has no name but a phonetic name, then its display will be set from the |
| // phonetic name. In this case, we still aggregate by the display name. |
| |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, null, null, "Yamada"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, null, null, "Yamada"); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Yamada"); |
| } |
| |
| public void testReaggregationWhenBecomesInvisible() { |
| Account account = new Account("accountName", "accountType"); |
| createAutoAddGroup(account); |
| |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, account); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder"); |
| |
| long rawContactId3 = RawContactUtil.createRawContact(mResolver, account); |
| DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder"); |
| |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId2, rawContactId3); |
| assertNotAggregated(rawContactId1, rawContactId2); |
| |
| // Hide by removing from all groups |
| removeGroupMemberships(rawContactId3); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Flynn Ryder"); |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId2, rawContactId3); |
| } |
| |
| public void testReaggregationWhenBecomesInvisibleSecondaryDataMatch() { |
| Account account = new Account("accountName", "accountType"); |
| createAutoAddGroup(account); |
| |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, account); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder"); |
| |
| long rawContactId3 = RawContactUtil.createRawContact(mResolver, account); |
| DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder"); |
| |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId2, rawContactId3); |
| assertNotAggregated(rawContactId1, rawContactId2); |
| |
| // Hide by removing from all groups |
| removeGroupMemberships(rawContactId3); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Flynn Ryder"); |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId2, rawContactId3); |
| } |
| |
| public void testReaggregationWhenBecomesVisible() { |
| Account account = new Account("accountName", "accountType"); |
| long groupId = createAutoAddGroup(account); |
| |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, account); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder"); |
| |
| long rawContactId3 = RawContactUtil.createRawContact(mResolver, account); |
| removeGroupMemberships(rawContactId3); |
| DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder"); |
| |
| assertAggregated(rawContactId1, rawContactId2, "Flynn Ryder"); |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId2, rawContactId3); |
| |
| insertGroupMembership(rawContactId3, groupId); |
| |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId2, rawContactId3); |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testNonSplitBecauseOfMultipleAffinitiesWhenOverridden() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_2); |
| long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_3); |
| assertAggregated(rawContactId1, rawContactId2); |
| assertAggregated(rawContactId1, rawContactId3); |
| setAggregationException( |
| AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); |
| assertAggregated(rawContactId1, rawContactId2); |
| assertAggregated(rawContactId1, rawContactId3); |
| |
| // The aggregate this raw contact could join has a raw contact from the same account, |
| // Let's re-aggregate the existing aggregate because of the ambiguity |
| long rawContactId4 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| assertAggregated(rawContactId1, rawContactId2); // Aggregation exception |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId1, rawContactId4); |
| assertNotAggregated(rawContactId3, rawContactId4); |
| } |
| |
| public void testNonSplitWhenIdentityMatch() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertIdentity(rawContactId1, "iden", "namespace"); |
| insertIdentity(rawContactId1, "iden2", "namespace"); |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_2); |
| insertIdentity(rawContactId2, "iden", "namespace"); |
| assertAggregated(rawContactId1, rawContactId2); |
| |
| long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| assertAggregated(rawContactId1, rawContactId2); |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId2, rawContactId3); |
| } |
| |
| public void testReAggregateToConnectedComponent() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertPhoneNumber(rawContactId1, "111"); |
| setRawContactCustomization(rawContactId1, 1, 1); |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_2); |
| insertPhoneNumber(rawContactId2, "111"); |
| setRawContactCustomization(rawContactId2, 1, 1); |
| long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_3); |
| insertIdentity(rawContactId3, "iden", "namespace"); |
| long rawContactId4 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| new Account("account_name_4", "account_type_4")); |
| insertIdentity(rawContactId4, "iden", "namespace"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| assertAggregated(rawContactId1, rawContactId3); |
| assertAggregated(rawContactId1, rawContactId4); |
| assertStoredValue(getContactUriForRawContact(rawContactId1), |
| Contacts.STARRED, 1); |
| assertStoredValue(getContactUriForRawContact(rawContactId4), |
| Contacts.SEND_TO_VOICEMAIL, 0); |
| |
| long rawContactId5 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| assertAggregated(rawContactId3, rawContactId4); |
| assertNotAggregated(rawContactId1, rawContactId3); |
| assertNotAggregated(rawContactId1, rawContactId5); |
| assertNotAggregated(rawContactId3, rawContactId5); |
| assertStoredValue(getContactUriForRawContact(rawContactId1), |
| Contacts.STARRED, 1); |
| assertStoredValue(getContactUriForRawContact(rawContactId1), |
| Contacts.SEND_TO_VOICEMAIL, 1); |
| |
| assertStoredValue(getContactUriForRawContact(rawContactId3), |
| Contacts.STARRED, 0); |
| assertStoredValue(getContactUriForRawContact(rawContactId3), |
| Contacts.SEND_TO_VOICEMAIL, 0); |
| |
| assertStoredValue(getContactUriForRawContact(rawContactId5), |
| Contacts.STARRED, 0); |
| assertStoredValue(getContactUriForRawContact(rawContactId5), |
| Contacts.SEND_TO_VOICEMAIL, 0); |
| } |
| |
| public void testNonAggregationFromDifferentAccountWithIdentityMisMatch() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertIdentity(rawContactId1, "iden1", "namespace"); |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| insertIdentity(rawContactId2, "iden2", "namespace"); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "John", "Doe"); |
| |
| // rawContact1 and rawContact2 have different identities on the same namespace, |
| // which prevent them to aggregate. |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testNonAggregationFromSameAccountWithoutAnyDataMatching() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testNonAggregationFromSameAccountNoCommonData() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertEmail(rawContactId1, "lightning1@android.com"); |
| insertPhoneNumber(rawContactId1, "111-222-3333"); |
| insertIdentity(rawContactId1, "iden1", "namespace"); |
| |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertEmail(rawContactId2, "lightning2@android.com"); |
| insertPhoneNumber(rawContactId2, "555-666-7777"); |
| insertIdentity(rawContactId1, "iden2", "namespace"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationFromSameAccountEmailSame_IgnoreCase() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertEmail(rawContactId1, "lightning@android.com"); |
| |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertEmail(rawContactId2, "lightning@android.com"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| |
| long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "Jane", "Doe", |
| ACCOUNT_1); |
| insertEmail(rawContactId3, "jane@android.com"); |
| |
| long rawContactId4 = RawContactUtil.createRawContactWithName(mResolver, "Jane", "Doe", |
| ACCOUNT_1); |
| insertEmail(rawContactId4, "JANE@ANDROID.COM"); |
| |
| assertAggregated(rawContactId3, rawContactId4); |
| } |
| |
| public void testNonAggregationFromSameAccountEmailDifferent() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertEmail(rawContactId1, "lightning1@android.com"); |
| |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertEmail(rawContactId2, "lightning2@android.com"); |
| insertEmail(rawContactId2, "lightning3@android.com"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationFromSameAccountIdentitySame() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertIdentity(rawContactId1, "iden", "namespace"); |
| |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertIdentity(rawContactId2, "iden", "namespace"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testNonAggregationFromSameAccountIdentityDifferent() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertIdentity(rawContactId1, "iden1", "namespace1"); |
| insertIdentity(rawContactId1, "iden2", "namespace2"); |
| |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertIdentity(rawContactId2, "iden2", "namespace1"); |
| insertIdentity(rawContactId2, "iden1", "namespace2"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationFromSameAccountPhoneNumberSame() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertPhoneNumber(rawContactId1, "111-222-3333"); |
| |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertPhoneNumber(rawContactId2, "111-222-3333"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationFromSameAccountPhoneNumberNormalizedSame() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertPhoneNumber(rawContactId1, "111-222-3333"); |
| |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertPhoneNumber(rawContactId2, "+1-111-222-3333"); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testNonAggregationFromSameAccountPhoneNumberDifferent() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertPhoneNumber(rawContactId1, "111-222-3333"); |
| |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", |
| ACCOUNT_1); |
| insertPhoneNumber(rawContactId2, "111-222-3334"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationSuggestionsBasedOnName() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Duane", null); |
| |
| // Exact name match |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Duane", null); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId1, rawContactId2); |
| |
| // Edit distance == 0.84 |
| long rawContactId3 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId3, "Dwayne", null); |
| |
| // Edit distance == 0.6 |
| long rawContactId4 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId4, "Donny", null); |
| |
| long contactId1 = queryContactId(rawContactId1); |
| long contactId2 = queryContactId(rawContactId2); |
| long contactId3 = queryContactId(rawContactId3); |
| |
| assertSuggestions(contactId1, contactId2, contactId3); |
| } |
| |
| public void testAggregationSuggestionsBasedOnPhoneNumber() { |
| |
| // Create two contacts that would not be aggregated because of name mismatch |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Lord", "Farquaad"); |
| insertPhoneNumber(rawContactId1, "(888)555-1236"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Talking", "Donkey"); |
| insertPhoneNumber(rawContactId2, "1(888)555-1236"); |
| |
| long contactId1 = queryContactId(rawContactId1); |
| long contactId2 = queryContactId(rawContactId2); |
| assertTrue(contactId1 != contactId2); |
| |
| assertSuggestions(contactId1, contactId2); |
| } |
| |
| public void testAggregationSuggestionsBasedOnEmailAddress() { |
| |
| // Create two contacts that would not be aggregated because of name mismatch |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Carl", "Fredricksen"); |
| insertEmail(rawContactId1, "up@android.com"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Charles", "Muntz"); |
| insertEmail(rawContactId2, "Up@Android.com"); |
| |
| long contactId1 = queryContactId(rawContactId1); |
| long contactId2 = queryContactId(rawContactId2); |
| assertTrue(contactId1 != contactId2); |
| |
| assertSuggestions(contactId1, contactId2); |
| } |
| |
| public void testAggregationSuggestionsBasedOnEmailAddressApproximateMatch() { |
| |
| // Create two contacts that would not be aggregated because of name mismatch |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Bob", null); |
| insertEmail(rawContactId1, "incredible@android.com"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Lucius", "Best"); |
| insertEmail(rawContactId2, "incrediball@android.com"); |
| |
| long contactId1 = queryContactId(rawContactId1); |
| long contactId2 = queryContactId(rawContactId2); |
| assertTrue(contactId1 != contactId2); |
| |
| assertSuggestions(contactId1, contactId2); |
| } |
| |
| public void testAggregationSuggestionsBasedOnNickname() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Peter", "Parker"); |
| insertNickname(rawContactId1, "Spider-Man"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Manny", "Spider"); |
| |
| long contactId1 = queryContactId(rawContactId1); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId1, rawContactId2); |
| |
| long contactId2 = queryContactId(rawContactId2); |
| assertSuggestions(contactId1, contactId2); |
| } |
| |
| public void testAggregationSuggestionsBasedOnNicknameMatchingName() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Clark", "Kent"); |
| insertNickname(rawContactId1, "Superman"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Roy", "Williams"); |
| insertNickname(rawContactId2, "superman"); |
| |
| long contactId1 = queryContactId(rawContactId1); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId1, rawContactId2); |
| |
| long contactId2 = queryContactId(rawContactId2); |
| assertSuggestions(contactId1, contactId2); |
| } |
| |
| public void testAggregationSuggestionsBasedOnCommonNickname() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Dick", "Cherry"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Richard", "Cherry"); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId1, rawContactId2); |
| |
| long contactId1 = queryContactId(rawContactId1); |
| long contactId2 = queryContactId(rawContactId2); |
| assertSuggestions(contactId1, contactId2); |
| } |
| |
| public void testAggregationSuggestionsBasedOnPhoneNumberWithFilter() { |
| |
| // Create two contacts that would not be aggregated because of name mismatch |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId1, "Lord", "Farquaad"); |
| insertPhoneNumber(rawContactId1, "(888)555-1236"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "Talking", "Donkey"); |
| insertPhoneNumber(rawContactId2, "1(888)555-1236"); |
| |
| long contactId1 = queryContactId(rawContactId1); |
| long contactId2 = queryContactId(rawContactId2); |
| assertTrue(contactId1 != contactId2); |
| |
| assertSuggestions(contactId1, "talk", contactId2); |
| assertSuggestions(contactId1, "don", contactId2); |
| assertSuggestions(contactId1, "", contactId2); |
| assertSuggestions(contactId1, "eddie"); |
| } |
| |
| public void testAggregationSuggestionsDontSuggestInvisible() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "first", "last", |
| ACCOUNT_1); |
| insertPhoneNumber(rawContactId1, "111-222-3333"); |
| insertNickname(rawContactId1, "Superman"); |
| insertEmail(rawContactId1, "incredible@android.com"); |
| |
| // Create another with the exact same name, phone number, nickname and email. |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "first", "last", |
| ACCOUNT_2); |
| insertPhoneNumber(rawContactId2, "111-222-3333"); |
| insertNickname(rawContactId2, "Superman"); |
| insertEmail(rawContactId2, "incredible@android.com"); |
| |
| // The aggregator should have joined them. Split them up. |
| setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, |
| rawContactId1, rawContactId2); |
| |
| long contactId1 = queryContactId(rawContactId1); |
| long contactId2 = queryContactId(rawContactId2); |
| |
| // Make sure they're different contacts. |
| MoreAsserts.assertNotEqual(contactId1, contactId2); |
| |
| // Contact 2 should be suggested. |
| assertSuggestions(contactId1, contactId2); |
| |
| // Make contact 2 invisible. |
| markInvisible(contactId2); |
| |
| // Now contact 2 shuldn't be suggested. |
| assertSuggestions(contactId1, new long[0]); |
| } |
| |
| public void testChoosePhotoSetBeforeAggregation() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId1, "donut", "donut_act"); |
| insertPhoto(rawContactId1); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId2, "cupcake", "cupcake_act"); |
| long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2)); |
| |
| long rawContactId3 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId3, "froyo", "froyo_act"); |
| insertPhoto(rawContactId3); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId2); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId3); |
| assertEquals(cupcakeId, queryPhotoId(queryContactId(rawContactId2))); |
| } |
| |
| public void testChoosePhotoSetAfterAggregation() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId1, "donut", "donut_act"); |
| insertPhoto(rawContactId1); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId2); |
| setContactAccount(rawContactId2, "cupcake", "cupcake_act"); |
| long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2)); |
| |
| long rawContactId3 = RawContactUtil.createRawContact(mResolver); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId3); |
| setContactAccount(rawContactId3, "froyo", "froyo_act"); |
| insertPhoto(rawContactId3); |
| |
| assertEquals(cupcakeId, queryPhotoId(queryContactId(rawContactId2))); |
| } |
| |
| // Note that for the following tests of photo aggregation, the accounts are being used to |
| // set the typical photo priority that each raw contact would have, based on |
| // SynchronousContactsProvider2.createPhotoPriorityResolver. The relative priorities |
| // specified there are: |
| // cupcake: 3 |
| // donut: 2 |
| // froyo: 1 |
| // <other>: 0 |
| |
| public void testChooseLargerPhotoByDimensions() { |
| // Donut photo is 256x256. |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId1, "donut", "donut_act"); |
| long normalEarthDataId = ContentUris.parseId( |
| insertPhoto(rawContactId1, R.drawable.earth_normal)); |
| long normalEarthPhotoFileId = getStoredLongValue( |
| ContentUris.withAppendedId(Data.CONTENT_URI, normalEarthDataId), |
| Photo.PHOTO_FILE_ID); |
| |
| // Cupcake would normally have priority, but its photo is 200x200. |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId2, "cupcake", "cupcake_act"); |
| insertPhoto(rawContactId2, R.drawable.earth_200); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId2); |
| |
| // Larger photo (by dimensions) wins. |
| assertEquals(normalEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); |
| } |
| |
| public void testChooseLargerPhotoByFileSize() { |
| // Donut photo is a 256x256 photo of a nebula. |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId1, "donut", "donut_act"); |
| long nebulaDataId = ContentUris.parseId( |
| insertPhoto(rawContactId1, R.drawable.nebula)); |
| long nebulaPhotoFileId = getStoredLongValue( |
| ContentUris.withAppendedId(Data.CONTENT_URI, nebulaDataId), |
| Photo.PHOTO_FILE_ID); |
| |
| // Cupcake would normally have priority, but its photo (of a galaxy) has the same dimensions |
| // as Donut's, but a smaller filesize. |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId2, "cupcake", "cupcake_act"); |
| insertPhoto(rawContactId2, R.drawable.galaxy); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId2); |
| |
| // Larger photo (by filesize) wins. |
| assertEquals(nebulaPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); |
| } |
| |
| public void testChooseFilePhotoOverThumbnail() { |
| // Donut photo is a 256x256 photo of Earth. |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId1, "donut", "donut_act"); |
| long normalEarthDataId = ContentUris.parseId( |
| insertPhoto(rawContactId1, R.drawable.earth_normal)); |
| long normalEarthPhotoFileId = getStoredLongValue( |
| ContentUris.withAppendedId(Data.CONTENT_URI, normalEarthDataId), |
| Photo.PHOTO_FILE_ID); |
| |
| // Cupcake would normally have priority, but its photo of Earth is thumbnail-sized. |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId2, "cupcake", "cupcake_act"); |
| insertPhoto(rawContactId2, R.drawable.earth_small); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId2); |
| |
| // Larger photo (by filesize) wins. |
| assertEquals(normalEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); |
| } |
| |
| public void testFallbackToAccountPriorityForSamePhoto() { |
| // Donut photo is a 256x256 photo of Earth. |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId1, "donut", "donut_act"); |
| insertPhoto(rawContactId1, R.drawable.earth_normal); |
| |
| // Cupcake has the same 256x256 photo of Earth. |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId2, "cupcake", "cupcake_act"); |
| long cupcakeEarthDataId = ContentUris.parseId( |
| insertPhoto(rawContactId2, R.drawable.earth_normal)); |
| long cupcakeEarthPhotoFileId = getStoredLongValue( |
| ContentUris.withAppendedId(Data.CONTENT_URI, cupcakeEarthDataId), |
| Photo.PHOTO_FILE_ID); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId2); |
| |
| // Cupcake's version of the photo wins, falling back to account priority. |
| assertEquals(cupcakeEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); |
| } |
| |
| public void testFallbackToAccountPriorityForDifferingThumbnails() { |
| // Donut photo is a 96x96 thumbnail of Earth. |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId1, "donut", "donut_act"); |
| insertPhoto(rawContactId1, R.drawable.earth_small); |
| |
| // Cupcake photo is the 96x96 "no contact" placeholder (smaller filesize than the Earth |
| // picture, but thumbnail filesizes are ignored in the aggregator). |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| setContactAccount(rawContactId2, "cupcake", "cupcake_act"); |
| long cupcakeDataId = ContentUris.parseId( |
| insertPhoto(rawContactId2, R.drawable.ic_contact_picture)); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, |
| rawContactId1, rawContactId2); |
| |
| // The Cupcake thumbnail wins, by account priority.. |
| assertEquals(cupcakeDataId, queryPhotoId(queryContactId(rawContactId1))); |
| } |
| |
| public void testDisplayNameSources() { |
| long rawContactId = RawContactUtil.createRawContact(mResolver); |
| long contactId = queryContactId(rawContactId); |
| |
| assertNull(queryDisplayName(contactId)); |
| |
| insertEmail(rawContactId, "eclair@android.com"); |
| assertEquals("eclair@android.com", queryDisplayName(contactId)); |
| |
| insertPhoneNumber(rawContactId, "800-555-5555"); |
| assertEquals("800-555-5555", queryDisplayName(contactId)); |
| |
| ContentValues values = new ContentValues(); |
| values.put(Organization.COMPANY, "Android"); |
| insertOrganization(rawContactId, values); |
| assertEquals("Android", queryDisplayName(contactId)); |
| |
| insertNickname(rawContactId, "Dro"); |
| assertEquals("Dro", queryDisplayName(contactId)); |
| |
| values.clear(); |
| values.put(StructuredName.GIVEN_NAME, "Eclair"); |
| values.put(StructuredName.FAMILY_NAME, "Android"); |
| DataUtil.insertStructuredName(mResolver, rawContactId, values); |
| assertEquals("Eclair Android", queryDisplayName(contactId)); |
| } |
| |
| public void testVerifiedName() { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "test1", "TEST1", |
| ACCOUNT_1); |
| storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.NAME_VERIFIED, "1"); |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "test2", "TEST2", |
| ACCOUNT_2); |
| long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "test3", |
| "TEST3 LONG", ACCOUNT_3); |
| |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, |
| rawContactId2); |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, |
| rawContactId3); |
| |
| long contactId = queryContactId(rawContactId1); |
| |
| // Should be the verified name |
| assertEquals("test1 TEST1", queryDisplayName(contactId)); |
| |
| // Mark a different name as verified - this should reset the NAME_VERIFIED field |
| // for the other rawContacts |
| storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.NAME_VERIFIED, "1"); |
| assertStoredValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.NAME_VERIFIED, 0); |
| assertEquals("test2 TEST2", queryDisplayName(contactId)); |
| |
| // Reset the NAME_VERIFIED flag - now the most complex of the three names should win |
| storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.NAME_VERIFIED, "0"); |
| assertEquals("test3 TEST3 LONG", queryDisplayName(contactId)); |
| } |
| |
| public void testAggregationModeSuspendedSeparateTransactions() { |
| |
| // Setting aggregation mode to SUSPENDED should prevent aggregation from happening |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| storeValue(RawContacts.CONTENT_URI, rawContactId1, |
| RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED); |
| Uri name1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "THE", "SAME"); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| storeValue(RawContacts.CONTENT_URI, rawContactId2, |
| RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED); |
| DataUtil.insertStructuredName(mResolver, rawContactId2, "THE", "SAME"); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| |
| // Changing aggregation mode to DEFAULT should change nothing |
| storeValue(RawContacts.CONTENT_URI, rawContactId1, |
| RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT); |
| storeValue(RawContacts.CONTENT_URI, rawContactId2, |
| RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT); |
| assertNotAggregated(rawContactId1, rawContactId2); |
| |
| // Changing the name should trigger aggregation |
| storeValue(name1, StructuredName.GIVEN_NAME, "the"); |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationModeInitializedAsSuspended() throws Exception { |
| |
| // Setting aggregation mode to SUSPENDED should prevent aggregation from happening |
| ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) |
| .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) |
| .build(); |
| ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) |
| .withValueBackReference(Data.RAW_CONTACT_ID, 0) |
| .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) |
| .withValue(StructuredName.GIVEN_NAME, "John") |
| .withValue(StructuredName.FAMILY_NAME, "Doe") |
| .build(); |
| ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) |
| .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) |
| .build(); |
| ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI) |
| .withValueBackReference(Data.RAW_CONTACT_ID, 2) |
| .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) |
| .withValue(StructuredName.GIVEN_NAME, "John") |
| .withValue(StructuredName.FAMILY_NAME, "Doe") |
| .build(); |
| ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) |
| .withSelection(RawContacts._ID + "=?", new String[1]) |
| .withSelectionBackReference(0, 0) |
| .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT) |
| .build(); |
| ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) |
| .withSelection(RawContacts._ID + "=?", new String[1]) |
| .withSelectionBackReference(0, 2) |
| .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT) |
| .build(); |
| |
| ContentProviderResult[] results = |
| mResolver.applyBatch(ContactsContract.AUTHORITY, |
| Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6)); |
| |
| long rawContactId1 = ContentUris.parseId(results[0].uri); |
| long rawContactId2 = ContentUris.parseId(results[2].uri); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationModeUpdatedToSuspended() throws Exception { |
| |
| // Setting aggregation mode to SUSPENDED should prevent aggregation from happening |
| ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) |
| .withValues(new ContentValues()) |
| .build(); |
| ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) |
| .withValueBackReference(Data.RAW_CONTACT_ID, 0) |
| .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) |
| .withValue(StructuredName.GIVEN_NAME, "John") |
| .withValue(StructuredName.FAMILY_NAME, "Doe") |
| .build(); |
| ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) |
| .withValues(new ContentValues()) |
| .build(); |
| ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI) |
| .withValueBackReference(Data.RAW_CONTACT_ID, 2) |
| .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) |
| .withValue(StructuredName.GIVEN_NAME, "John") |
| .withValue(StructuredName.FAMILY_NAME, "Doe") |
| .build(); |
| ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) |
| .withSelection(RawContacts._ID + "=?", new String[1]) |
| .withSelectionBackReference(0, 0) |
| .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) |
| .build(); |
| ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) |
| .withSelection(RawContacts._ID + "=?", new String[1]) |
| .withSelectionBackReference(0, 2) |
| .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) |
| .build(); |
| |
| ContentProviderResult[] results = |
| mResolver.applyBatch(ContactsContract.AUTHORITY, |
| Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6)); |
| |
| long rawContactId1 = ContentUris.parseId(results[0].uri); |
| long rawContactId2 = ContentUris.parseId(results[2].uri); |
| |
| assertNotAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationModeSuspendedOverriddenByAggException() throws Exception { |
| ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) |
| .withValue(RawContacts.ACCOUNT_NAME, "a") |
| .withValue(RawContacts.ACCOUNT_TYPE, "b") |
| .build(); |
| ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) |
| .withValueBackReference(Data.RAW_CONTACT_ID, 0) |
| .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) |
| .withValue(StructuredName.GIVEN_NAME, "John") |
| .withValue(StructuredName.FAMILY_NAME, "Doe") |
| .build(); |
| ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) |
| .withValue(RawContacts.ACCOUNT_NAME, "c") |
| .withValue(RawContacts.ACCOUNT_TYPE, "d") |
| .build(); |
| ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI) |
| .withValueBackReference(Data.RAW_CONTACT_ID, 2) |
| .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) |
| .withValue(StructuredName.GIVEN_NAME, "John") |
| .withValue(StructuredName.FAMILY_NAME, "Doe") |
| .build(); |
| ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) |
| .withSelection(RawContacts._ID + "=?", new String[1]) |
| .withSelectionBackReference(0, 0) |
| .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) |
| .build(); |
| ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) |
| .withSelection(RawContacts._ID + "=?", new String[1]) |
| .withSelectionBackReference(0, 2) |
| .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) |
| .build(); |
| |
| // Checking that aggregation mode SUSPENDED should be overridden by inserting |
| // an explicit aggregation exception |
| ContentProviderOperation cpo7 = |
| ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI) |
| .withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, 0) |
| .withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, 2) |
| .withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER) |
| .build(); |
| |
| ContentProviderResult[] results = |
| mResolver.applyBatch(ContactsContract.AUTHORITY, |
| Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6, cpo7)); |
| |
| long rawContactId1 = ContentUris.parseId(results[0].uri); |
| long rawContactId2 = ContentUris.parseId(results[2].uri); |
| |
| assertAggregated(rawContactId1, rawContactId2); |
| } |
| |
| public void testAggregationSuggestionsQueryBuilderWithContactId() throws Exception { |
| Uri uri = AggregationSuggestions.builder().setContactId(12).setLimit(7).build(); |
| assertEquals("content://com.android.contacts/contacts/12/suggestions?limit=7", |
| uri.toString()); |
| } |
| |
| public void testAggregationSuggestionsQueryBuilderWithValues() throws Exception { |
| Uri uri = AggregationSuggestions.builder() |
| .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "name1") |
| .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "name2") |
| .addParameter(AggregationSuggestions.PARAMETER_MATCH_EMAIL, "email1") |
| .addParameter(AggregationSuggestions.PARAMETER_MATCH_EMAIL, "email2") |
| .addParameter(AggregationSuggestions.PARAMETER_MATCH_PHONE, "phone1") |
| .addParameter(AggregationSuggestions.PARAMETER_MATCH_NICKNAME, "nickname1") |
| .setLimit(7) |
| .build(); |
| assertEquals("content://com.android.contacts/contacts/0/suggestions?" |
| + "limit=7" |
| + "&query=name%3Aname1" |
| + "&query=name%3Aname2" |
| + "&query=email%3Aemail1" |
| + "&query=email%3Aemail2" |
| + "&query=phone%3Aphone1" |
| + "&query=nickname%3Anickname1", uri.toString()); |
| } |
| |
| public void testAggregatedStatusUpdate() { |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver); |
| Uri dataUri1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "john", "doe"); |
| insertStatusUpdate(ContentUris.parseId(dataUri1), StatusUpdates.AWAY, "Green", 100, |
| StatusUpdates.CAPABILITY_HAS_CAMERA); |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver); |
| Uri dataUri2 = DataUtil.insertStructuredName(mResolver, rawContactId2, "john", "doe"); |
| insertStatusUpdate(ContentUris.parseId(dataUri2), StatusUpdates.AVAILABLE, "Red", 50, |
| StatusUpdates.CAPABILITY_HAS_CAMERA); |
| setAggregationException( |
| AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); |
| |
| assertStoredValue(getContactUriForRawContact(rawContactId1), |
| Contacts.CONTACT_STATUS, "Green"); |
| |
| // When we split these two raw contacts, their respective statuses should be restored |
| setAggregationException( |
| AggregationExceptions.TYPE_KEEP_SEPARATE, rawContactId1, rawContactId2); |
| |
| assertStoredValue(getContactUriForRawContact(rawContactId1), |
| Contacts.CONTACT_STATUS, "Green"); |
| |
| assertStoredValue(getContactUriForRawContact(rawContactId2), |
| Contacts.CONTACT_STATUS, "Red"); |
| } |
| |
| public void testAggregationSuggestionsByName() throws Exception { |
| long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "first1", "last1"); |
| long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "first2", "last2"); |
| |
| Uri uri = AggregationSuggestions.builder() |
| .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "last1 first1") |
| .build(); |
| |
| Cursor cursor = mResolver.query( |
| uri, new String[] { Contacts._ID, Contacts.DISPLAY_NAME }, null, null, null); |
| |
| assertEquals(1, cursor.getCount()); |
| |
| cursor.moveToFirst(); |
| |
| ContentValues values = new ContentValues(); |
| values.put(Contacts._ID, queryContactId(rawContactId1)); |
| values.put(Contacts.DISPLAY_NAME, "first1 last1"); |
| assertCursorValues(cursor, values); |
| cursor.close(); |
| } |
| |
| public void testAggregation_clearSuperPrimary() { |
| // Three types of mime-type super primary merging are tested here |
| // 1. both raw contacts have super primary phone numbers |
| // 2. both raw contacts have emails, but only one has super primary email |
| // 3. only raw contact1 has organizations and it has set the super primary organization |
| ContentValues values = new ContentValues(); |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| Uri uri_phone1 = insertPhoneNumber(rawContactId1, "(222)222-2222", false, false); |
| Uri uri_email1 = insertEmail(rawContactId1, "one@gmail.com", true, true); |
| values.clear(); |
| values.put(Organization.COMPANY, "Monsters Inc"); |
| Uri uri_org1 = insertOrganization(rawContactId1, values, true, true); |
| values.clear(); |
| values.put(Organization.TITLE, "CEO"); |
| Uri uri_org2 = insertOrganization(rawContactId1, values, false, false); |
| |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); |
| Uri uri_phone2 = insertPhoneNumber(rawContactId2, "(333)333-3333", false, false); |
| Uri uri_email2 = insertEmail(rawContactId2, "two@gmail.com", false, false); |
| |
| // Two raw contacts with same phone number will trigger the aggregation |
| Uri uri_phone3 = insertPhoneNumber(rawContactId1, "(111)111-1111", true, true); |
| Uri uri_phone4 = insertPhoneNumber(rawContactId2, "1(111)111-1111", true, true); |
| |
| // After aggregation, the super primary flag should be cleared for both case 1 and case 2, |
| // i.e., phone and email mime-types. Only case 3, i.e. organization mime-type, has the |
| // super primary flag unchanged. |
| assertAggregated(rawContactId1, rawContactId2); |
| assertSuperPrimary(ContentUris.parseId(uri_phone1), false); |
| assertSuperPrimary(ContentUris.parseId(uri_phone2), false); |
| assertSuperPrimary(ContentUris.parseId(uri_phone3), false); |
| assertSuperPrimary(ContentUris.parseId(uri_phone4), false); |
| |
| assertSuperPrimary(ContentUris.parseId(uri_email1), false); |
| assertSuperPrimary(ContentUris.parseId(uri_email2), false); |
| |
| assertSuperPrimary(ContentUris.parseId(uri_org1), true); |
| assertSuperPrimary(ContentUris.parseId(uri_org2), false); |
| } |
| |
| public void testAggregation_clearSuperPrimarySingleMimetype() { |
| // Setup: two raw contacts, each has a single name. One of the names is super primary. |
| long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); |
| final Uri uri = DataUtil.insertStructuredName(mResolver, rawContactId1, "name1", |
| null, null, /* isSuperPrimary = */ true); |
| |
| // Sanity check. |
| assertStoredValue(uri, Data.IS_SUPER_PRIMARY, 1); |
| |
| // Action: aggregate |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, |
| rawContactId2); |
| |
| // Verify: name is still super primary |
| assertStoredValue(uri, Data.IS_SUPER_PRIMARY, 1); |
| } |
| |
| public void testNotAggregate_TooManyRawContactsInCandidate() { |
| long preId= 0; |
| for (int i = 0; i < ContactAggregator.AGGREGATION_CONTACT_SIZE_LIMIT; i++) { |
| long id = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe"); |
| if (i > 0) { |
| setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, preId, id); |
| } |
| preId = id; |
| } |
| // Although the newly added raw contact matches the names with other raw contacts, |
| // but the best matching contact has already meets the size limit, so keep the new raw |
| // contact separate from other raw contacts. |
| long newId = RawContactUtil.createRawContact(mResolver, |
| new Account("account_new", "new account type")); |
| DataUtil.insertStructuredName(mResolver, newId, "John", "Doe"); |
| assertNotAggregated(preId, newId); |
| assertTrue(queryContactId(newId) > 0); |
| } |
| |
| public void testFindConnectedRawContacts() { |
| Set<Long> rawContactIdSet = new HashSet<Long>(); |
| rawContactIdSet.addAll(Arrays.asList(1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l)); |
| |
| Multimap<Long, Long> matchingrawIdPairs = HashMultimap.create(); |
| matchingrawIdPairs.put(1l, 2l); |
| matchingrawIdPairs.put(2l, 1l); |
| |
| matchingrawIdPairs.put(1l, 7l); |
| matchingrawIdPairs.put(7l, 1l); |
| |
| matchingrawIdPairs.put(2l, 3l); |
| matchingrawIdPairs.put(3l, 2l); |
| |
| matchingrawIdPairs.put(2l, 8l); |
| matchingrawIdPairs.put(8l, 2l); |
| |
| matchingrawIdPairs.put(8l, 9l); |
| matchingrawIdPairs.put(9l, 8l); |
| |
| matchingrawIdPairs.put(4l, 5l); |
| matchingrawIdPairs.put(5l, 4l); |
| |
| Set<Set<Long>> actual = ContactAggregator.findConnectedComponents(rawContactIdSet, |
| matchingrawIdPairs); |
| |
| Set<Set<Long>> expected = new HashSet<Set<Long>>(); |
| Set<Long> result1 = new HashSet<Long>(); |
| result1.addAll(Arrays.asList(1l, 2l, 3l, 7l, 8l, 9l)); |
| Set<Long> result2 = new HashSet<Long>(); |
| result2.addAll(Arrays.asList(4l, 5l)); |
| Set<Long> result3 = new HashSet<Long>(); |
| result3.addAll(Arrays.asList(6l)); |
| expected.addAll(Arrays.asList(result1, result2, result3)); |
| |
| assertEquals(expected, actual); |
| } |
| |
| private void assertSuggestions(long contactId, long... suggestions) { |
| final Uri aggregateUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); |
| Uri uri = Uri.withAppendedPath(aggregateUri, |
| Contacts.AggregationSuggestions.CONTENT_DIRECTORY); |
| assertSuggestions(uri, suggestions); |
| } |
| |
| private void assertSuggestions(long contactId, String filter, long... suggestions) { |
| final Uri aggregateUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); |
| Uri uri = Uri.withAppendedPath(Uri.withAppendedPath(aggregateUri, |
| Contacts.AggregationSuggestions.CONTENT_DIRECTORY), Uri.encode(filter)); |
| assertSuggestions(uri, suggestions); |
| } |
| |
| private void assertSuggestions(Uri uri, long... suggestions) { |
| final Cursor cursor = mResolver.query(uri, |
| new String[] { Contacts._ID, Contacts.CONTACT_PRESENCE }, |
| null, null, null); |
| |
| try { |
| assertEquals(suggestions.length, cursor.getCount()); |
| |
| for (int i = 0; i < suggestions.length; i++) { |
| cursor.moveToNext(); |
| assertEquals(suggestions[i], cursor.getLong(0)); |
| } |
| } finally { |
| TestUtils.dumpCursor(cursor); |
| } |
| |
| cursor.close(); |
| } |
| |
| private void assertDisplayNameEquals(long contactId, long rawContactId) { |
| |
| String contactDisplayName = queryDisplayName(contactId); |
| |
| Cursor c = queryRawContact(rawContactId); |
| assertTrue(c.moveToFirst()); |
| String rawDisplayName = c.getString(c.getColumnIndex(RawContacts.DISPLAY_NAME_PRIMARY)); |
| c.close(); |
| |
| assertTrue(contactDisplayName != null); |
| assertTrue(rawDisplayName != null); |
| assertEquals(rawDisplayName, contactDisplayName); |
| } |
| } |