ContactAggregatorTest.java revision df1e589415a68f4427219459ced28638d382132b
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 17package com.android.providers.contacts.aggregation; 18 19import android.accounts.Account; 20import android.content.ContentProviderOperation; 21import android.content.ContentProviderResult; 22import android.content.ContentUris; 23import android.content.ContentValues; 24import android.database.Cursor; 25import android.net.Uri; 26import android.provider.ContactsContract; 27import android.provider.ContactsContract.AggregationExceptions; 28import android.provider.ContactsContract.CommonDataKinds.Organization; 29import android.provider.ContactsContract.CommonDataKinds.StructuredName; 30import android.provider.ContactsContract.Contacts; 31import android.provider.ContactsContract.Contacts.AggregationSuggestions; 32import android.provider.ContactsContract.Contacts.Photo; 33import android.provider.ContactsContract.Data; 34import android.provider.ContactsContract.RawContacts; 35import android.provider.ContactsContract.StatusUpdates; 36import android.test.MoreAsserts; 37import android.test.suitebuilder.annotation.MediumTest; 38 39import com.android.providers.contacts.BaseContactsProvider2Test; 40import com.android.providers.contacts.TestUtils; 41import com.android.providers.contacts.tests.R; 42import com.android.providers.contacts.testutil.DataUtil; 43import com.android.providers.contacts.testutil.RawContactUtil; 44 45import 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 57public 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@android.com"); 342 343 long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); 344 insertEmail(rawContactId2, "lightning@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@android.com"); 352 353 long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); 354 DataUtil.insertStructuredName(mResolver, rawContactId2, "Lightning", "McQueen"); 355 insertEmail(rawContactId2, "mcqueen@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@android.com"); 364 365 long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); 366 insertEmail(rawContactId2, "doc@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@android.com"); 375 376 long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); 377 DataUtil.insertStructuredName(mResolver, rawContactId2, "Luigi", "Guido"); 378 insertEmail(rawContactId2, "hicky@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@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@android.com"); 763 insertPhoneNumber(rawContactId2, "555-666-7777"); 764 insertIdentity(rawContactId1, "iden2", "namespace"); 765 766 assertNotAggregated(rawContactId1, rawContactId2); 767 } 768 769 public void testAggregationFromSameAccountEmailSame_IgnoreCase() { 770 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 771 ACCOUNT_1); 772 insertEmail(rawContactId1, "lightning@android.com"); 773 774 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 775 ACCOUNT_1); 776 insertEmail(rawContactId2, "lightning@android.com"); 777 778 assertAggregated(rawContactId1, rawContactId2); 779 780 long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "Jane", "Doe", 781 ACCOUNT_1); 782 insertEmail(rawContactId3, "jane@android.com"); 783 784 long rawContactId4 = RawContactUtil.createRawContactWithName(mResolver, "Jane", "Doe", 785 ACCOUNT_1); 786 insertEmail(rawContactId4, "JANE@ANDROID.COM"); 787 788 assertAggregated(rawContactId3, rawContactId4); 789 } 790 791 public void testNonAggregationFromSameAccountEmailDifferent() { 792 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 793 ACCOUNT_1); 794 insertEmail(rawContactId1, "lightning1@android.com"); 795 796 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 797 ACCOUNT_1); 798 insertEmail(rawContactId2, "lightning2@android.com"); 799 insertEmail(rawContactId2, "lightning3@android.com"); 800 801 assertNotAggregated(rawContactId1, rawContactId2); 802 } 803 804 public void testAggregationFromSameAccountIdentitySame() { 805 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 806 ACCOUNT_1); 807 insertIdentity(rawContactId1, "iden", "namespace"); 808 809 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 810 ACCOUNT_1); 811 insertIdentity(rawContactId2, "iden", "namespace"); 812 813 assertAggregated(rawContactId1, rawContactId2); 814 } 815 816 public void testNonAggregationFromSameAccountIdentityDifferent() { 817 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 818 ACCOUNT_1); 819 insertIdentity(rawContactId1, "iden1", "namespace1"); 820 insertIdentity(rawContactId1, "iden2", "namespace2"); 821 822 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 823 ACCOUNT_1); 824 insertIdentity(rawContactId2, "iden2", "namespace1"); 825 insertIdentity(rawContactId2, "iden1", "namespace2"); 826 827 assertNotAggregated(rawContactId1, rawContactId2); 828 } 829 830 public void testAggregationFromSameAccountPhoneNumberSame() { 831 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 832 ACCOUNT_1); 833 insertPhoneNumber(rawContactId1, "111-222-3333"); 834 835 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 836 ACCOUNT_1); 837 insertPhoneNumber(rawContactId2, "111-222-3333"); 838 839 assertAggregated(rawContactId1, rawContactId2); 840 } 841 842 public void testAggregationFromSameAccountPhoneNumberNormalizedSame() { 843 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 844 ACCOUNT_1); 845 insertPhoneNumber(rawContactId1, "111-222-3333"); 846 847 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 848 ACCOUNT_1); 849 insertPhoneNumber(rawContactId2, "+1-111-222-3333"); 850 851 assertAggregated(rawContactId1, rawContactId2); 852 } 853 854 public void testNonAggregationFromSameAccountPhoneNumberDifferent() { 855 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 856 ACCOUNT_1); 857 insertPhoneNumber(rawContactId1, "111-222-3333"); 858 859 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 860 ACCOUNT_1); 861 insertPhoneNumber(rawContactId2, "111-222-3334"); 862 863 assertNotAggregated(rawContactId1, rawContactId2); 864 } 865 866 public void testAggregationSuggestionsBasedOnName() { 867 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 868 DataUtil.insertStructuredName(mResolver, rawContactId1, "Duane", null); 869 870 // Exact name match 871 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 872 DataUtil.insertStructuredName(mResolver, rawContactId2, "Duane", null); 873 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 874 rawContactId1, rawContactId2); 875 876 // Edit distance == 0.84 877 long rawContactId3 = RawContactUtil.createRawContact(mResolver); 878 DataUtil.insertStructuredName(mResolver, rawContactId3, "Dwayne", null); 879 880 // Edit distance == 0.6 881 long rawContactId4 = RawContactUtil.createRawContact(mResolver); 882 DataUtil.insertStructuredName(mResolver, rawContactId4, "Donny", null); 883 884 long contactId1 = queryContactId(rawContactId1); 885 long contactId2 = queryContactId(rawContactId2); 886 long contactId3 = queryContactId(rawContactId3); 887 888 assertSuggestions(contactId1, contactId2, contactId3); 889 } 890 891 public void testAggregationSuggestionsBasedOnPhoneNumber() { 892 893 // Create two contacts that would not be aggregated because of name mismatch 894 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 895 DataUtil.insertStructuredName(mResolver, rawContactId1, "Lord", "Farquaad"); 896 insertPhoneNumber(rawContactId1, "(888)555-1236"); 897 898 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 899 DataUtil.insertStructuredName(mResolver, rawContactId2, "Talking", "Donkey"); 900 insertPhoneNumber(rawContactId2, "1(888)555-1236"); 901 902 long contactId1 = queryContactId(rawContactId1); 903 long contactId2 = queryContactId(rawContactId2); 904 assertTrue(contactId1 != contactId2); 905 906 assertSuggestions(contactId1, contactId2); 907 } 908 909 public void testAggregationSuggestionsBasedOnEmailAddress() { 910 911 // Create two contacts that would not be aggregated because of name mismatch 912 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 913 DataUtil.insertStructuredName(mResolver, rawContactId1, "Carl", "Fredricksen"); 914 insertEmail(rawContactId1, "up@android.com"); 915 916 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 917 DataUtil.insertStructuredName(mResolver, rawContactId2, "Charles", "Muntz"); 918 insertEmail(rawContactId2, "Up@Android.com"); 919 920 long contactId1 = queryContactId(rawContactId1); 921 long contactId2 = queryContactId(rawContactId2); 922 assertTrue(contactId1 != contactId2); 923 924 assertSuggestions(contactId1, contactId2); 925 } 926 927 public void testAggregationSuggestionsBasedOnEmailAddressApproximateMatch() { 928 929 // Create two contacts that would not be aggregated because of name mismatch 930 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 931 DataUtil.insertStructuredName(mResolver, rawContactId1, "Bob", null); 932 insertEmail(rawContactId1, "incredible@android.com"); 933 934 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 935 DataUtil.insertStructuredName(mResolver, rawContactId2, "Lucius", "Best"); 936 insertEmail(rawContactId2, "incrediball@android.com"); 937 938 long contactId1 = queryContactId(rawContactId1); 939 long contactId2 = queryContactId(rawContactId2); 940 assertTrue(contactId1 != contactId2); 941 942 assertSuggestions(contactId1, contactId2); 943 } 944 945 public void testAggregationSuggestionsBasedOnNickname() { 946 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 947 DataUtil.insertStructuredName(mResolver, rawContactId1, "Peter", "Parker"); 948 insertNickname(rawContactId1, "Spider-Man"); 949 950 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 951 DataUtil.insertStructuredName(mResolver, rawContactId2, "Manny", "Spider"); 952 953 long contactId1 = queryContactId(rawContactId1); 954 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 955 rawContactId1, rawContactId2); 956 957 long contactId2 = queryContactId(rawContactId2); 958 assertSuggestions(contactId1, contactId2); 959 } 960 961 public void testAggregationSuggestionsBasedOnNicknameMatchingName() { 962 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 963 DataUtil.insertStructuredName(mResolver, rawContactId1, "Clark", "Kent"); 964 insertNickname(rawContactId1, "Superman"); 965 966 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 967 DataUtil.insertStructuredName(mResolver, rawContactId2, "Roy", "Williams"); 968 insertNickname(rawContactId2, "superman"); 969 970 long contactId1 = queryContactId(rawContactId1); 971 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 972 rawContactId1, rawContactId2); 973 974 long contactId2 = queryContactId(rawContactId2); 975 assertSuggestions(contactId1, contactId2); 976 } 977 978 public void testAggregationSuggestionsBasedOnCommonNickname() { 979 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 980 DataUtil.insertStructuredName(mResolver, rawContactId1, "Dick", "Cherry"); 981 982 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 983 DataUtil.insertStructuredName(mResolver, rawContactId2, "Richard", "Cherry"); 984 985 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 986 rawContactId1, rawContactId2); 987 988 long contactId1 = queryContactId(rawContactId1); 989 long contactId2 = queryContactId(rawContactId2); 990 assertSuggestions(contactId1, contactId2); 991 } 992 993 public void testAggregationSuggestionsBasedOnPhoneNumberWithFilter() { 994 995 // Create two contacts that would not be aggregated because of name mismatch 996 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 997 DataUtil.insertStructuredName(mResolver, rawContactId1, "Lord", "Farquaad"); 998 insertPhoneNumber(rawContactId1, "(888)555-1236"); 999 1000 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1001 DataUtil.insertStructuredName(mResolver, rawContactId2, "Talking", "Donkey"); 1002 insertPhoneNumber(rawContactId2, "1(888)555-1236"); 1003 1004 long contactId1 = queryContactId(rawContactId1); 1005 long contactId2 = queryContactId(rawContactId2); 1006 assertTrue(contactId1 != contactId2); 1007 1008 assertSuggestions(contactId1, "talk", contactId2); 1009 assertSuggestions(contactId1, "don", contactId2); 1010 assertSuggestions(contactId1, "", contactId2); 1011 assertSuggestions(contactId1, "eddie"); 1012 } 1013 1014 public void testAggregationSuggestionsDontSuggestInvisible() { 1015 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "first", "last", 1016 ACCOUNT_1); 1017 insertPhoneNumber(rawContactId1, "111-222-3333"); 1018 insertNickname(rawContactId1, "Superman"); 1019 insertEmail(rawContactId1, "incredible@android.com"); 1020 1021 // Create another with the exact same name, phone number, nickname and email. 1022 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "first", "last", 1023 ACCOUNT_2); 1024 insertPhoneNumber(rawContactId2, "111-222-3333"); 1025 insertNickname(rawContactId2, "Superman"); 1026 insertEmail(rawContactId2, "incredible@android.com"); 1027 1028 // The aggregator should have joined them. Split them up. 1029 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 1030 rawContactId1, rawContactId2); 1031 1032 long contactId1 = queryContactId(rawContactId1); 1033 long contactId2 = queryContactId(rawContactId2); 1034 1035 // Make sure they're different contacts. 1036 MoreAsserts.assertNotEqual(contactId1, contactId2); 1037 1038 // Contact 2 should be suggested. 1039 assertSuggestions(contactId1, contactId2); 1040 1041 // Make contact 2 invisible. 1042 markInvisible(contactId2); 1043 1044 // Now contact 2 shuldn't be suggested. 1045 assertSuggestions(contactId1, new long[0]); 1046 } 1047 1048 public void testChoosePhotoSetBeforeAggregation() { 1049 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1050 setContactAccount(rawContactId1, "donut", "donut_act"); 1051 insertPhoto(rawContactId1); 1052 1053 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1054 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1055 long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2)); 1056 1057 long rawContactId3 = RawContactUtil.createRawContact(mResolver); 1058 setContactAccount(rawContactId3, "froyo", "froyo_act"); 1059 insertPhoto(rawContactId3); 1060 1061 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1062 rawContactId1, rawContactId2); 1063 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1064 rawContactId1, rawContactId3); 1065 assertEquals(cupcakeId, queryPhotoId(queryContactId(rawContactId2))); 1066 } 1067 1068 public void testChoosePhotoSetAfterAggregation() { 1069 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1070 setContactAccount(rawContactId1, "donut", "donut_act"); 1071 insertPhoto(rawContactId1); 1072 1073 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1074 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1075 rawContactId1, rawContactId2); 1076 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1077 long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2)); 1078 1079 long rawContactId3 = RawContactUtil.createRawContact(mResolver); 1080 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1081 rawContactId1, rawContactId3); 1082 setContactAccount(rawContactId3, "froyo", "froyo_act"); 1083 insertPhoto(rawContactId3); 1084 1085 assertEquals(cupcakeId, queryPhotoId(queryContactId(rawContactId2))); 1086 } 1087 1088 // Note that for the following tests of photo aggregation, the accounts are being used to 1089 // set the typical photo priority that each raw contact would have, based on 1090 // SynchronousContactsProvider2.createPhotoPriorityResolver. The relative priorities 1091 // specified there are: 1092 // cupcake: 3 1093 // donut: 2 1094 // froyo: 1 1095 // <other>: 0 1096 1097 public void testChooseLargerPhotoByDimensions() { 1098 // Donut photo is 256x256. 1099 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1100 setContactAccount(rawContactId1, "donut", "donut_act"); 1101 long normalEarthDataId = ContentUris.parseId( 1102 insertPhoto(rawContactId1, R.drawable.earth_normal)); 1103 long normalEarthPhotoFileId = getStoredLongValue( 1104 ContentUris.withAppendedId(Data.CONTENT_URI, normalEarthDataId), 1105 Photo.PHOTO_FILE_ID); 1106 1107 // Cupcake would normally have priority, but its photo is 200x200. 1108 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1109 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1110 insertPhoto(rawContactId2, R.drawable.earth_200); 1111 1112 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1113 rawContactId1, rawContactId2); 1114 1115 // Larger photo (by dimensions) wins. 1116 assertEquals(normalEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); 1117 } 1118 1119 public void testChooseLargerPhotoByFileSize() { 1120 // Donut photo is a 256x256 photo of a nebula. 1121 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1122 setContactAccount(rawContactId1, "donut", "donut_act"); 1123 long nebulaDataId = ContentUris.parseId( 1124 insertPhoto(rawContactId1, R.drawable.nebula)); 1125 long nebulaPhotoFileId = getStoredLongValue( 1126 ContentUris.withAppendedId(Data.CONTENT_URI, nebulaDataId), 1127 Photo.PHOTO_FILE_ID); 1128 1129 // Cupcake would normally have priority, but its photo (of a galaxy) has the same dimensions 1130 // as Donut's, but a smaller filesize. 1131 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1132 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1133 insertPhoto(rawContactId2, R.drawable.galaxy); 1134 1135 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1136 rawContactId1, rawContactId2); 1137 1138 // Larger photo (by filesize) wins. 1139 assertEquals(nebulaPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); 1140 } 1141 1142 public void testChooseFilePhotoOverThumbnail() { 1143 // Donut photo is a 256x256 photo of Earth. 1144 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1145 setContactAccount(rawContactId1, "donut", "donut_act"); 1146 long normalEarthDataId = ContentUris.parseId( 1147 insertPhoto(rawContactId1, R.drawable.earth_normal)); 1148 long normalEarthPhotoFileId = getStoredLongValue( 1149 ContentUris.withAppendedId(Data.CONTENT_URI, normalEarthDataId), 1150 Photo.PHOTO_FILE_ID); 1151 1152 // Cupcake would normally have priority, but its photo of Earth is thumbnail-sized. 1153 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1154 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1155 insertPhoto(rawContactId2, R.drawable.earth_small); 1156 1157 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1158 rawContactId1, rawContactId2); 1159 1160 // Larger photo (by filesize) wins. 1161 assertEquals(normalEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); 1162 } 1163 1164 public void testFallbackToAccountPriorityForSamePhoto() { 1165 // Donut photo is a 256x256 photo of Earth. 1166 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1167 setContactAccount(rawContactId1, "donut", "donut_act"); 1168 insertPhoto(rawContactId1, R.drawable.earth_normal); 1169 1170 // Cupcake has the same 256x256 photo of Earth. 1171 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1172 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1173 long cupcakeEarthDataId = ContentUris.parseId( 1174 insertPhoto(rawContactId2, R.drawable.earth_normal)); 1175 long cupcakeEarthPhotoFileId = getStoredLongValue( 1176 ContentUris.withAppendedId(Data.CONTENT_URI, cupcakeEarthDataId), 1177 Photo.PHOTO_FILE_ID); 1178 1179 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1180 rawContactId1, rawContactId2); 1181 1182 // Cupcake's version of the photo wins, falling back to account priority. 1183 assertEquals(cupcakeEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); 1184 } 1185 1186 public void testFallbackToAccountPriorityForDifferingThumbnails() { 1187 // Donut photo is a 96x96 thumbnail of Earth. 1188 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1189 setContactAccount(rawContactId1, "donut", "donut_act"); 1190 insertPhoto(rawContactId1, R.drawable.earth_small); 1191 1192 // Cupcake photo is the 96x96 "no contact" placeholder (smaller filesize than the Earth 1193 // picture, but thumbnail filesizes are ignored in the aggregator). 1194 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1195 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1196 long cupcakeDataId = ContentUris.parseId( 1197 insertPhoto(rawContactId2, R.drawable.ic_contact_picture)); 1198 1199 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1200 rawContactId1, rawContactId2); 1201 1202 // The Cupcake thumbnail wins, by account priority.. 1203 assertEquals(cupcakeDataId, queryPhotoId(queryContactId(rawContactId1))); 1204 } 1205 1206 public void testDisplayNameSources() { 1207 long rawContactId = RawContactUtil.createRawContact(mResolver); 1208 long contactId = queryContactId(rawContactId); 1209 1210 assertNull(queryDisplayName(contactId)); 1211 1212 insertEmail(rawContactId, "eclair@android.com"); 1213 assertEquals("eclair@android.com", queryDisplayName(contactId)); 1214 1215 insertPhoneNumber(rawContactId, "800-555-5555"); 1216 assertEquals("800-555-5555", queryDisplayName(contactId)); 1217 1218 ContentValues values = new ContentValues(); 1219 values.put(Organization.COMPANY, "Android"); 1220 insertOrganization(rawContactId, values); 1221 assertEquals("Android", queryDisplayName(contactId)); 1222 1223 insertNickname(rawContactId, "Dro"); 1224 assertEquals("Dro", queryDisplayName(contactId)); 1225 1226 values.clear(); 1227 values.put(StructuredName.GIVEN_NAME, "Eclair"); 1228 values.put(StructuredName.FAMILY_NAME, "Android"); 1229 DataUtil.insertStructuredName(mResolver, rawContactId, values); 1230 assertEquals("Eclair Android", queryDisplayName(contactId)); 1231 } 1232 1233 public void testVerifiedName() { 1234 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "test1", "TEST1", 1235 ACCOUNT_1); 1236 storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.NAME_VERIFIED, "1"); 1237 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "test2", "TEST2", 1238 ACCOUNT_2); 1239 long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "test3", 1240 "TEST3 LONG", ACCOUNT_3); 1241 1242 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, 1243 rawContactId2); 1244 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, 1245 rawContactId3); 1246 1247 long contactId = queryContactId(rawContactId1); 1248 1249 // Should be the verified name 1250 assertEquals("test1 TEST1", queryDisplayName(contactId)); 1251 1252 // Mark a different name as verified - this should reset the NAME_VERIFIED field 1253 // for the other rawContacts 1254 storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.NAME_VERIFIED, "1"); 1255 assertStoredValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.NAME_VERIFIED, 0); 1256 assertEquals("test2 TEST2", queryDisplayName(contactId)); 1257 1258 // Reset the NAME_VERIFIED flag - now the most complex of the three names should win 1259 storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.NAME_VERIFIED, "0"); 1260 assertEquals("test3 TEST3 LONG", queryDisplayName(contactId)); 1261 } 1262 1263 public void testAggregationModeSuspendedSeparateTransactions() { 1264 1265 // Setting aggregation mode to SUSPENDED should prevent aggregation from happening 1266 long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); 1267 storeValue(RawContacts.CONTENT_URI, rawContactId1, 1268 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED); 1269 Uri name1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "THE", "SAME"); 1270 1271 long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); 1272 storeValue(RawContacts.CONTENT_URI, rawContactId2, 1273 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED); 1274 DataUtil.insertStructuredName(mResolver, rawContactId2, "THE", "SAME"); 1275 1276 assertNotAggregated(rawContactId1, rawContactId2); 1277 1278 // Changing aggregation mode to DEFAULT should change nothing 1279 storeValue(RawContacts.CONTENT_URI, rawContactId1, 1280 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT); 1281 storeValue(RawContacts.CONTENT_URI, rawContactId2, 1282 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT); 1283 assertNotAggregated(rawContactId1, rawContactId2); 1284 1285 // Changing the name should trigger aggregation 1286 storeValue(name1, StructuredName.GIVEN_NAME, "the"); 1287 assertAggregated(rawContactId1, rawContactId2); 1288 } 1289 1290 public void testAggregationModeInitializedAsSuspended() throws Exception { 1291 1292 // Setting aggregation mode to SUSPENDED should prevent aggregation from happening 1293 ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1294 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1295 .build(); 1296 ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1297 .withValueBackReference(Data.RAW_CONTACT_ID, 0) 1298 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1299 .withValue(StructuredName.GIVEN_NAME, "John") 1300 .withValue(StructuredName.FAMILY_NAME, "Doe") 1301 .build(); 1302 ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1303 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1304 .build(); 1305 ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1306 .withValueBackReference(Data.RAW_CONTACT_ID, 2) 1307 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1308 .withValue(StructuredName.GIVEN_NAME, "John") 1309 .withValue(StructuredName.FAMILY_NAME, "Doe") 1310 .build(); 1311 ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1312 .withSelection(RawContacts._ID + "=?", new String[1]) 1313 .withSelectionBackReference(0, 0) 1314 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT) 1315 .build(); 1316 ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1317 .withSelection(RawContacts._ID + "=?", new String[1]) 1318 .withSelectionBackReference(0, 2) 1319 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT) 1320 .build(); 1321 1322 ContentProviderResult[] results = 1323 mResolver.applyBatch(ContactsContract.AUTHORITY, 1324 Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6)); 1325 1326 long rawContactId1 = ContentUris.parseId(results[0].uri); 1327 long rawContactId2 = ContentUris.parseId(results[2].uri); 1328 1329 assertNotAggregated(rawContactId1, rawContactId2); 1330 } 1331 1332 public void testAggregationModeUpdatedToSuspended() throws Exception { 1333 1334 // Setting aggregation mode to SUSPENDED should prevent aggregation from happening 1335 ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1336 .withValues(new ContentValues()) 1337 .build(); 1338 ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1339 .withValueBackReference(Data.RAW_CONTACT_ID, 0) 1340 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1341 .withValue(StructuredName.GIVEN_NAME, "John") 1342 .withValue(StructuredName.FAMILY_NAME, "Doe") 1343 .build(); 1344 ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1345 .withValues(new ContentValues()) 1346 .build(); 1347 ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1348 .withValueBackReference(Data.RAW_CONTACT_ID, 2) 1349 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1350 .withValue(StructuredName.GIVEN_NAME, "John") 1351 .withValue(StructuredName.FAMILY_NAME, "Doe") 1352 .build(); 1353 ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1354 .withSelection(RawContacts._ID + "=?", new String[1]) 1355 .withSelectionBackReference(0, 0) 1356 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1357 .build(); 1358 ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1359 .withSelection(RawContacts._ID + "=?", new String[1]) 1360 .withSelectionBackReference(0, 2) 1361 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1362 .build(); 1363 1364 ContentProviderResult[] results = 1365 mResolver.applyBatch(ContactsContract.AUTHORITY, 1366 Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6)); 1367 1368 long rawContactId1 = ContentUris.parseId(results[0].uri); 1369 long rawContactId2 = ContentUris.parseId(results[2].uri); 1370 1371 assertNotAggregated(rawContactId1, rawContactId2); 1372 } 1373 1374 public void testAggregationModeSuspendedOverriddenByAggException() throws Exception { 1375 ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1376 .withValue(RawContacts.ACCOUNT_NAME, "a") 1377 .withValue(RawContacts.ACCOUNT_TYPE, "b") 1378 .build(); 1379 ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1380 .withValueBackReference(Data.RAW_CONTACT_ID, 0) 1381 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1382 .withValue(StructuredName.GIVEN_NAME, "John") 1383 .withValue(StructuredName.FAMILY_NAME, "Doe") 1384 .build(); 1385 ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1386 .withValue(RawContacts.ACCOUNT_NAME, "c") 1387 .withValue(RawContacts.ACCOUNT_TYPE, "d") 1388 .build(); 1389 ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1390 .withValueBackReference(Data.RAW_CONTACT_ID, 2) 1391 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1392 .withValue(StructuredName.GIVEN_NAME, "John") 1393 .withValue(StructuredName.FAMILY_NAME, "Doe") 1394 .build(); 1395 ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1396 .withSelection(RawContacts._ID + "=?", new String[1]) 1397 .withSelectionBackReference(0, 0) 1398 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1399 .build(); 1400 ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1401 .withSelection(RawContacts._ID + "=?", new String[1]) 1402 .withSelectionBackReference(0, 2) 1403 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1404 .build(); 1405 1406 // Checking that aggregation mode SUSPENDED should be overridden by inserting 1407 // an explicit aggregation exception 1408 ContentProviderOperation cpo7 = 1409 ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI) 1410 .withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, 0) 1411 .withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, 2) 1412 .withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER) 1413 .build(); 1414 1415 ContentProviderResult[] results = 1416 mResolver.applyBatch(ContactsContract.AUTHORITY, 1417 Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6, cpo7)); 1418 1419 long rawContactId1 = ContentUris.parseId(results[0].uri); 1420 long rawContactId2 = ContentUris.parseId(results[2].uri); 1421 1422 assertAggregated(rawContactId1, rawContactId2); 1423 } 1424 1425 public void testAggregationSuggestionsQueryBuilderWithContactId() throws Exception { 1426 Uri uri = AggregationSuggestions.builder().setContactId(12).setLimit(7).build(); 1427 assertEquals("content://com.android.contacts/contacts/12/suggestions?limit=7", 1428 uri.toString()); 1429 } 1430 1431 public void testAggregationSuggestionsQueryBuilderWithValues() throws Exception { 1432 Uri uri = AggregationSuggestions.builder() 1433 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "name1") 1434 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "name2") 1435 .addParameter(AggregationSuggestions.PARAMETER_MATCH_EMAIL, "email1") 1436 .addParameter(AggregationSuggestions.PARAMETER_MATCH_EMAIL, "email2") 1437 .addParameter(AggregationSuggestions.PARAMETER_MATCH_PHONE, "phone1") 1438 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NICKNAME, "nickname1") 1439 .setLimit(7) 1440 .build(); 1441 assertEquals("content://com.android.contacts/contacts/0/suggestions?" 1442 + "limit=7" 1443 + "&query=name%3Aname1" 1444 + "&query=name%3Aname2" 1445 + "&query=email%3Aemail1" 1446 + "&query=email%3Aemail2" 1447 + "&query=phone%3Aphone1" 1448 + "&query=nickname%3Anickname1", uri.toString()); 1449 } 1450 1451 public void testAggregatedStatusUpdate() { 1452 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1453 Uri dataUri1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "john", "doe"); 1454 insertStatusUpdate(ContentUris.parseId(dataUri1), StatusUpdates.AWAY, "Green", 100, 1455 StatusUpdates.CAPABILITY_HAS_CAMERA); 1456 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1457 Uri dataUri2 = DataUtil.insertStructuredName(mResolver, rawContactId2, "john", "doe"); 1458 insertStatusUpdate(ContentUris.parseId(dataUri2), StatusUpdates.AVAILABLE, "Red", 50, 1459 StatusUpdates.CAPABILITY_HAS_CAMERA); 1460 setAggregationException( 1461 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 1462 1463 assertStoredValue(getContactUriForRawContact(rawContactId1), 1464 Contacts.CONTACT_STATUS, "Green"); 1465 1466 // When we split these two raw contacts, their respective statuses should be restored 1467 setAggregationException( 1468 AggregationExceptions.TYPE_KEEP_SEPARATE, rawContactId1, rawContactId2); 1469 1470 assertStoredValue(getContactUriForRawContact(rawContactId1), 1471 Contacts.CONTACT_STATUS, "Green"); 1472 1473 assertStoredValue(getContactUriForRawContact(rawContactId2), 1474 Contacts.CONTACT_STATUS, "Red"); 1475 } 1476 1477 public void testAggregationSuggestionsByName() throws Exception { 1478 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "first1", "last1"); 1479 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "first2", "last2"); 1480 1481 Uri uri = AggregationSuggestions.builder() 1482 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "last1 first1") 1483 .build(); 1484 1485 Cursor cursor = mResolver.query( 1486 uri, new String[] { Contacts._ID, Contacts.DISPLAY_NAME }, null, null, null); 1487 1488 assertEquals(1, cursor.getCount()); 1489 1490 cursor.moveToFirst(); 1491 1492 ContentValues values = new ContentValues(); 1493 values.put(Contacts._ID, queryContactId(rawContactId1)); 1494 values.put(Contacts.DISPLAY_NAME, "first1 last1"); 1495 assertCursorValues(cursor, values); 1496 cursor.close(); 1497 } 1498 1499 public void testAggregation_clearSuperPrimary() { 1500 // Three types of mime-type super primary merging are tested here 1501 // 1. both raw contacts have super primary phone numbers 1502 // 2. both raw contacts have emails, but only one has super primary email 1503 // 3. only raw contact1 has organizations and it has set the super primary organization 1504 ContentValues values = new ContentValues(); 1505 long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); 1506 Uri uri_phone1 = insertPhoneNumber(rawContactId1, "(222)222-2222", false, false); 1507 Uri uri_email1 = insertEmail(rawContactId1, "one@gmail.com", true, true); 1508 values.clear(); 1509 values.put(Organization.COMPANY, "Monsters Inc"); 1510 Uri uri_org1 = insertOrganization(rawContactId1, values, true, true); 1511 values.clear(); 1512 values.put(Organization.TITLE, "CEO"); 1513 Uri uri_org2 = insertOrganization(rawContactId1, values, false, false); 1514 1515 long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); 1516 Uri uri_phone2 = insertPhoneNumber(rawContactId2, "(333)333-3333", false, false); 1517 Uri uri_email2 = insertEmail(rawContactId2, "two@gmail.com", false, false); 1518 1519 // Two raw contacts with same phone number will trigger the aggregation 1520 Uri uri_phone3 = insertPhoneNumber(rawContactId1, "(111)111-1111", true, true); 1521 Uri uri_phone4 = insertPhoneNumber(rawContactId2, "1(111)111-1111", true, true); 1522 1523 // After aggregation, the super primary flag should be cleared for both case 1 and case 2, 1524 // i.e., phone and email mime-types. Only case 3, i.e. organization mime-type, has the 1525 // super primary flag unchanged. 1526 assertAggregated(rawContactId1, rawContactId2); 1527 assertSuperPrimary(ContentUris.parseId(uri_phone1), false); 1528 assertSuperPrimary(ContentUris.parseId(uri_phone2), false); 1529 assertSuperPrimary(ContentUris.parseId(uri_phone3), false); 1530 assertSuperPrimary(ContentUris.parseId(uri_phone4), false); 1531 1532 assertSuperPrimary(ContentUris.parseId(uri_email1), false); 1533 assertSuperPrimary(ContentUris.parseId(uri_email2), false); 1534 1535 assertSuperPrimary(ContentUris.parseId(uri_org1), true); 1536 assertSuperPrimary(ContentUris.parseId(uri_org2), false); 1537 } 1538 1539 private void assertSuggestions(long contactId, long... suggestions) { 1540 final Uri aggregateUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1541 Uri uri = Uri.withAppendedPath(aggregateUri, 1542 Contacts.AggregationSuggestions.CONTENT_DIRECTORY); 1543 assertSuggestions(uri, suggestions); 1544 } 1545 1546 private void assertSuggestions(long contactId, String filter, long... suggestions) { 1547 final Uri aggregateUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1548 Uri uri = Uri.withAppendedPath(Uri.withAppendedPath(aggregateUri, 1549 Contacts.AggregationSuggestions.CONTENT_DIRECTORY), Uri.encode(filter)); 1550 assertSuggestions(uri, suggestions); 1551 } 1552 1553 private void assertSuggestions(Uri uri, long... suggestions) { 1554 final Cursor cursor = mResolver.query(uri, 1555 new String[] { Contacts._ID, Contacts.CONTACT_PRESENCE }, 1556 null, null, null); 1557 1558 try { 1559 assertEquals(suggestions.length, cursor.getCount()); 1560 1561 for (int i = 0; i < suggestions.length; i++) { 1562 cursor.moveToNext(); 1563 assertEquals(suggestions[i], cursor.getLong(0)); 1564 } 1565 } finally { 1566 TestUtils.dumpCursor(cursor); 1567 } 1568 1569 cursor.close(); 1570 } 1571 1572 private void assertDisplayNameEquals(long contactId, long rawContactId) { 1573 1574 String contactDisplayName = queryDisplayName(contactId); 1575 1576 Cursor c = queryRawContact(rawContactId); 1577 assertTrue(c.moveToFirst()); 1578 String rawDisplayName = c.getString(c.getColumnIndex(RawContacts.DISPLAY_NAME_PRIMARY)); 1579 c.close(); 1580 1581 assertTrue(contactDisplayName != null); 1582 assertTrue(rawDisplayName != null); 1583 assertEquals(rawDisplayName, contactDisplayName); 1584 } 1585} 1586