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